Ejemplo n.º 1
0
Archivo: song.py Proyecto: slo0ey/gd.py
 def official(cls,
              id: int,
              server_style: bool = True,
              *,
              client: Optional[Client] = None) -> Song:
     data = Converter.to_normal_song(id, server_style)
     return cls(**data, client=client)
Ejemplo n.º 2
0
    def from_data(cls, data: ExtDict, client: Client) -> Gauntlet:
        try:
            level_ids = tuple(map(int, data.get(Index.GAUNTLET_LEVEL_IDS, "").split(",")))
        except ValueError:
            level_ids = ()

        gid = data.getcast(Index.GAUNTLET_ID, 0, int)
        name = Converter.get_gauntlet_name(gid)

        return cls(id=gid, name=name, level_ids=level_ids, client=client)
Ejemplo n.º 3
0
 def __repr__(self) -> str:
     info = {
         "account_id": self.account_id,
         "name": repr(self.name),
         "id": self.id,
         "place": Converter.to_ordinal(self.place),
         "stars": self.stars,
         "demons": self.demons,
         "cp": self.cp,
     }
     return make_repr(self, info)
Ejemplo n.º 4
0
    async def get_level_info(self, level_id: int = 0) -> Tuple[ExtDict, ExtDict, ExtDict]:
        # level data, creator, song
        assert level_id >= -2, "Invalid Level ID provided."

        if level_id < 0:
            type, number, cooldown = await self.get_timely_info(level_id)
        else:
            type, number, cooldown = 0, -1, -1

        ext = {"101": type, "102": number, "103": cooldown}

        codes = {-1: MissingAccess(f"Failed to get a level. Given ID: {level_id}")}

        payload = Params().create_new().put_definer("levelid", level_id).finish()
        resp = await self.http.request(Route.DOWNLOAD_LEVEL, payload, error_codes=codes)

        level_data = Parser().split("#").take(0).split(":").add_ext(ext).should_map().parse(resp)

        real_id = level_data.getcast(Index.LEVEL_ID, 0, int)

        payload = (
            Params()
            .create_new()
            .put_definer("search", real_id)
            .put_filters(Filters.setup_empty())
            .finish()
        )
        resp = await self.http.request(Route.LEVEL_SEARCH, payload, error_codes=codes)

        if not resp or resp.count("#") < 2:
            raise codes.get(-1)

        data = resp.split("#")

        # getting song
        song_data = data[2]

        if not song_data:
            song = Converter.to_normal_song(level_data.getcast(Index.LEVEL_AUDIO_TRACK, 0, int))
        else:
            song = Parser().with_split("~|~").should_map().parse(song_data)

        # getting creator
        creator_data = data[1]

        if not creator_data:
            id, name, account_id = (0, "unknown", 0)
        else:
            id, name, account_id = creator_data.split(":")

        creator = ExtDict(id=id, name=name, account_id=account_id)

        return level_data, creator, song
Ejemplo n.º 5
0
    def get_level_difficulty(self) -> Union[LevelDifficulty, DemonDifficulty]:
        """Compute actual level difficulty and return the enum."""
        address = self.read_type(self.ptr_type, 0x3222D0, 0x164, 0x22C, 0x114)

        is_demon, is_auto, difficulty, demon_difficulty = (
            self.read(Bool, address + 0x29C),
            self.read(Bool, address + 0x2B0),
            self.read(UInt32, address + 0x1E4),
            self.read(UInt32, address + 0x2A0),
        )

        return Converter.convert_level_difficulty(difficulty, demon_difficulty,
                                                  is_demon, is_auto)
Ejemplo n.º 6
0
    def get_level_difficulty(self) -> Union[LevelDifficulty, DemonDifficulty]:
        address = self.read_bytes(self.PTR_LEN, 0x3222D0, 0x164, 0x22C, 0x114).as_int()

        is_demon, is_auto, diff, demon_diff = (
            self.read_at(1, address + 0x29C).as_bool(),
            self.read_at(1, address + 0x2B0).as_bool(),
            self.read_at(4, address + 0x1E4).as_int(),
            self.read_at(4, address + 0x2A0).as_int(),
        )

        return Converter.convert_level_difficulty(
            diff=diff, demon_diff=demon_diff, is_demon=is_demon, is_auto=is_auto
        )
Ejemplo n.º 7
0
    def __getitem__(self, item: Any) -> Any:
        try:
            return super().__getitem__(item)

        except KeyError:
            from gd.utils.converter import Converter

            try:
                return super().__getitem__(Converter.snake_to_camel(item))

            except KeyError:
                pass

            raise
Ejemplo n.º 8
0
    async def update_profile(self, settings: Dict[str, int], *, client: Client) -> None:
        settings_cased = {Converter.snake_to_camel(name): value for name, value in settings.items()}

        rs = Coder.gen_rs()

        req_chk_params = [client.account_id]
        req_chk_params.extend(
            settings.get(param, 0)
            for param in (
                "user_coins",
                "demons",
                "stars",
                "coins",
                "icon_type",
                "icon",
                "diamonds",
                "acc_icon",
                "acc_ship",
                "acc_ball",
                "acc_bird",
                "acc_dart",
                "acc_robot",
                "acc_glow",
                "acc_spider",
                "acc_explosion",
            )
        )

        chk = Coder.gen_chk(type="userscore", values=req_chk_params)

        payload = (
            Params()
            .create_new()
            .put_definer("accountid", client.account_id)
            .put_password(client.encodedpass)
            .put_username(client.name)
            .put_seed(rs)
            .put_seed(chk, suffix=str(2))
            .finish()
        )

        payload.update(settings_cased)

        resp = await self.http.request(Route.UPDATE_USER_SCORE, payload)

        if not resp > 0:
            raise MissingAccess(f"Failed to update profile of a client: {client!r}")
Ejemplo n.º 9
0
    def from_data(cls, data: ExtDict, client: Client) -> MapPack:
        try:
            level_ids = tuple(map(int, data.get(Index.MAP_PACK_LEVEL_IDS, "").split(",")))
        except ValueError:
            level_ids = ()

        color_string = data.get(Index.MAP_PACK_COLOR, "255,255,255")
        color = Color.from_rgb(*map(int, color_string.split(",")))

        difficulty = Converter.value_to_pack_difficulty(
            data.getcast(Index.MAP_PACK_DIFFICULTY, 0, int)
        )

        return cls(
            id=data.getcast(Index.MAP_PACK_ID, 0, int),
            name=data.get(Index.MAP_PACK_NAME, "unknown"),
            level_ids=level_ids,
            stars=data.getcast(Index.MAP_PACK_STARS, 0, int),
            coins=data.getcast(Index.MAP_PACK_COINS, 0, int),
            difficulty=difficulty,
            color=color,
            client=client,
        )
Ejemplo n.º 10
0
    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,
        )
Ejemplo n.º 11
0
    async def upload_level(
        self,
        data: str,
        name: str,
        level_id: int,
        version: int,
        length: LevelLength,
        audio_track: int,
        desc: str,
        song_id: int,
        is_auto: bool,
        original: int,
        two_player: bool,
        objects: int,
        coins: int,
        stars: int,
        unlisted: bool,
        ldm: bool,
        password: Optional[Union[int, str]],
        copyable: bool,
        *,
        client: Client,
    ) -> int:
        data = Coder.zip(data)
        extra_string = "_".join(map(str, (0 for _ in range(55))))
        desc = Coder.do_base64(desc)

        upload_seed = Coder.gen_level_upload_seed(data)
        seed2 = Coder.gen_chk(type="level", values=[upload_seed])
        seed = Coder.gen_rs()

        pwd = 0

        if copyable and password is None:
            pwd = 1

        check, add = str(password), 1000000

        if check.isdigit() and int(check) < add:
            pwd = add + int(password)

        payload = (
            Params()
            .create_new()
            .put_definer("accountid", client.account_id)
            .put_definer("levelid", level_id)
            .put_definer("song", song_id)
            .put_seed(seed)
            .put_seed(seed2, suffix=2)
            .put_seed(0, prefix="wt")
            .put_seed(0, prefix="wt", suffix=2)
            .put_password(client.encodedpass)
            .put_username(client.name)
            .finish()
        )

        options = {
            "level_name": name,
            "level_desc": desc,
            "level_version": version,
            "level_length": length.value,
            "audio_track": audio_track,
            "auto": int(is_auto),
            "original": int(original),
            "two_player": int(two_player),
            "objects": objects,
            "coins": coins,
            "requested_stars": stars,
            "unlisted": int(unlisted),
            "ldm": int(ldm),
            "password": pwd,
            "level_string": data,
            "extra_string": extra_string,
            "level_info": "H4sIAAAAAAAAC_NIrVQoyUgtStVRCMpPSi0qUbDStwYAsgpl1RUAAAA=",
        }

        payload_cased = {
            Converter.snake_to_camel(key): str(value) for key, value in options.items()
        }

        payload.update(payload_cased)

        level_id = await self.http.request(Route.UPLOAD_LEVEL, payload)

        if level_id == -1:
            raise MissingAccess("Failed to upload a level.")

        return level_id
Ejemplo n.º 12
0
 def _ord_index(self) -> Optional[str]:
     if self.index is not None:
         return Converter.to_ordinal(self.index)
Ejemplo n.º 13
0
 def _ord_index(self) -> str:
     if self.index is not None:
         return Converter.to_ordinal(self.index)