Beispiel #1
0
    def __format_profile(self, cardids: List[str], profile: ValidatedDict, settings: ValidatedDict, exact: bool) -> Dict[str, Any]:
        base = {
            'name': profile.get_str('name'),
            'cards': cardids,
            'registered': settings.get_int('first_play_timestamp', -1),
            'updated': settings.get_int('last_play_timestamp', -1),
            'plays': settings.get_int('total_plays', -1),
            'match': 'exact' if exact else 'partial',
        }

        if self.game == GameConstants.DDR:
            base.update(self.__format_ddr_profile(profile, exact))
        if self.game == GameConstants.IIDX:
            base.update(self.__format_iidx_profile(profile, exact))
        if self.game == GameConstants.JUBEAT:
            base.update(self.__format_jubeat_profile(profile, exact))
        if self.game == GameConstants.MUSECA:
            base.update(self.__format_museca_profile(profile, exact))
        if self.game == GameConstants.POPN_MUSIC:
            base.update(self.__format_popn_profile(profile, exact))
        if self.game == GameConstants.REFLEC_BEAT:
            base.update(self.__format_reflec_profile(profile, exact))
        if self.game == GameConstants.SDVX:
            base.update(self.__format_sdvx_profile(profile, exact))

        return base
Beispiel #2
0
 def format_profile(self, profile: ValidatedDict, playstats: ValidatedDict) -> Dict[str, Any]:
     return {
         'name': profile.get_str('name'),
         'extid': ID.format_extid(profile.get_int('extid')),
         'first_play_time': playstats.get_int('first_play_timestamp'),
         'last_play_time': playstats.get_int('last_play_timestamp'),
     }
Beispiel #3
0
    def __format_iidx_profile(self, profile: ValidatedDict) -> Dict[str, Any]:
        updates: Dict[str, Any] = {
            'qpro': {},
        }

        area = profile.get_int('area', -1)
        if area != -1:
            updates['pid'] = area

        qpro = profile.get_dict('qpro')
        head = qpro.get_int('head', -1)
        if head != -1:
            updates['qpro']['head'] = head
        hair = qpro.get_int('hair', -1)
        if hair != -1:
            updates['qpro']['hair'] = hair
        face = qpro.get_int('face', -1)
        if face != -1:
            updates['qpro']['face'] = face
        body = qpro.get_int('body', -1)
        if body != -1:
            updates['qpro']['body'] = body
        hand = qpro.get_int('hand', -1)
        if hand != -1:
            updates['qpro']['hand'] = hand

        return updates
Beispiel #4
0
    def format_conversion(self, userid: UserID,
                          profile: ValidatedDict) -> Node:
        root = Node.void('playerdata')

        root.add_child(Node.string('name', profile.get_str('name', 'なし')))
        root.add_child(Node.s16('chara', profile.get_int('chara', -1)))
        root.add_child(Node.s32('option', profile.get_int('option', 0)))
        root.add_child(Node.u8('version', 0))
        root.add_child(Node.u8('kind', 0))
        root.add_child(Node.u8('season', 0))

        clear_medal = [0] * self.GAME_MAX_MUSIC_ID

        scores = self.data.remote.music.get_scores(self.game, self.version,
                                                   userid)
        for score in scores:
            if score.id > self.GAME_MAX_MUSIC_ID:
                continue

            # Skip any scores for chart types we don't support
            if score.chart not in [
                    self.CHART_TYPE_EASY,
                    self.CHART_TYPE_NORMAL,
                    self.CHART_TYPE_HYPER,
                    self.CHART_TYPE_EX,
            ]:
                continue

            clear_medal[score.id] = clear_medal[
                score.id] | self.__format_medal_for_score(score)

        root.add_child(Node.u16_array('clear_medal', clear_medal))

        return root
Beispiel #5
0
    def format_profile(self, profile: ValidatedDict, playstats: ValidatedDict) -> Dict[str, Any]:
        name = 'なし'  # Nothing
        shop = '未設定'  # Not set
        shop_area = '未設定'  # Not set

        for i in range(len(profile['strdatas'])):
            strdata = profile['strdatas'][i]

            # Figure out the profile type
            csvs = strdata.split(b',')
            if len(csvs) < 2:
                # Not long enough to care about
                continue
            datatype = csvs[1].decode('ascii')
            if datatype != 'IBBDAT00':
                # Not the right profile type requested
                continue

            name = self.__update_value(name, csvs[27])
            shop = self.__update_value(shop, csvs[30])
            shop_area = self.__update_value(shop_area, csvs[31])

        return {
            'name': name,
            'extid': ID.format_extid(profile.get_int('extid')),
            'shop': shop,
            'shop_area': shop_area,
            'first_play_time': playstats.get_int('first_play_timestamp'),
            'last_play_time': playstats.get_int('last_play_timestamp'),
            'plays': playstats.get_int('total_plays'),
        }
Beispiel #6
0
    def get_play_statistics(self, userid: UserID) -> ValidatedDict:
        """
        Given a user ID, get the play statistics.

        Note that games wishing to use this when generating profiles to send to
        a game should call update_play_statistics when parsing a profile save.

        Parameters:
            userid - The user ID we are binding the profile for.

        Returns a dictionary optionally containing the following attributes:
            total_plays - Integer count of total plays for this game series
            first_play_timestamp - Unix timestamp of first play time
            last_play_timestamp - Unix timestamp of last play time
            last_play_date - List of ints in the form of [YYYY, MM, DD] of last play date
            today_plays - Number of times played today
            total_days - Total individual days played
            consecutive_days - Number of consecutive days played at this time.
        """
        if RemoteUser.is_remote(userid):
            return ValidatedDict({})
        settings = self.data.local.game.get_settings(self.game, userid)
        if settings is None:
            return ValidatedDict({})
        return settings
Beispiel #7
0
 def format_profile(self, profile: ValidatedDict,
                    playstats: ValidatedDict) -> Dict[str, Any]:
     formatted_profile = super().format_profile(profile, playstats)
     formatted_profile['plays'] = playstats.get_int('total_plays')
     formatted_profile['emblem'] = self.format_emblem(
         profile.get_dict('last').get_int_array('emblem', 5))
     return formatted_profile
Beispiel #8
0
 def format_qpro(self, qpro_dict: ValidatedDict) -> Dict[str, Any]:
     return {
         'body': qpro_dict.get_int('body'),
         'face': qpro_dict.get_int('face'),
         'hair': qpro_dict.get_int('hair'),
         'hand': qpro_dict.get_int('hand'),
         'head': qpro_dict.get_int('head'),
     }
Beispiel #9
0
    def format_conversion(self, userid: UserID, profile: ValidatedDict) -> Node:
        # Circular import, ugh
        from bemani.backend.popn.lapistoria import PopnMusicLapistoria

        root = Node.void('playerdata')

        root.add_child(Node.string('name', profile.get_str('name', 'なし')))
        root.add_child(Node.s16('chara', profile.get_int('chara', -1)))
        root.add_child(Node.s32('option', profile.get_int('option', 0)))
        root.add_child(Node.s8('result', 1))

        scores = self.data.remote.music.get_scores(self.game, self.version, userid)
        for score in scores:
            if score.id > self.GAME_MAX_MUSIC_ID:
                continue

            # Skip any scores for chart types we don't support
            if score.chart not in [
                self.CHART_TYPE_EASY,
                self.CHART_TYPE_NORMAL,
                self.CHART_TYPE_HYPER,
                self.CHART_TYPE_EX,
            ]:
                continue

            points = score.points
            medal = score.data.get_int('medal')

            music = Node.void('music')
            root.add_child(music)
            music.add_child(Node.s16('music_num', score.id))
            music.add_child(Node.u8('sheet_num', {
                self.CHART_TYPE_EASY: PopnMusicLapistoria.GAME_CHART_TYPE_EASY,
                self.CHART_TYPE_NORMAL: PopnMusicLapistoria.GAME_CHART_TYPE_NORMAL,
                self.CHART_TYPE_HYPER: PopnMusicLapistoria.GAME_CHART_TYPE_HYPER,
                self.CHART_TYPE_EX: PopnMusicLapistoria.GAME_CHART_TYPE_EX,
            }[score.chart]))
            music.add_child(Node.s16('cnt', score.plays))
            music.add_child(Node.s32('score', 0))
            music.add_child(Node.u8('clear_type', 0))
            music.add_child(Node.s32('old_score', points))
            music.add_child(Node.u8('old_clear_type', {
                self.PLAY_MEDAL_CIRCLE_FAILED: PopnMusicLapistoria.GAME_PLAY_MEDAL_CIRCLE_FAILED,
                self.PLAY_MEDAL_DIAMOND_FAILED: PopnMusicLapistoria.GAME_PLAY_MEDAL_DIAMOND_FAILED,
                self.PLAY_MEDAL_STAR_FAILED: PopnMusicLapistoria.GAME_PLAY_MEDAL_STAR_FAILED,
                self.PLAY_MEDAL_EASY_CLEAR: PopnMusicLapistoria.GAME_PLAY_MEDAL_EASY_CLEAR,
                self.PLAY_MEDAL_CIRCLE_CLEARED: PopnMusicLapistoria.GAME_PLAY_MEDAL_CIRCLE_CLEARED,
                self.PLAY_MEDAL_DIAMOND_CLEARED: PopnMusicLapistoria.GAME_PLAY_MEDAL_DIAMOND_CLEARED,
                self.PLAY_MEDAL_STAR_CLEARED: PopnMusicLapistoria.GAME_PLAY_MEDAL_STAR_CLEARED,
                self.PLAY_MEDAL_CIRCLE_FULL_COMBO: PopnMusicLapistoria.GAME_PLAY_MEDAL_CIRCLE_FULL_COMBO,
                self.PLAY_MEDAL_DIAMOND_FULL_COMBO: PopnMusicLapistoria.GAME_PLAY_MEDAL_DIAMOND_FULL_COMBO,
                self.PLAY_MEDAL_STAR_FULL_COMBO: PopnMusicLapistoria.GAME_PLAY_MEDAL_STAR_FULL_COMBO,
                self.PLAY_MEDAL_PERFECT: PopnMusicLapistoria.GAME_PLAY_MEDAL_PERFECT,
            }[medal]))

        return root
Beispiel #10
0
    def __format_profile(self, profile: ValidatedDict) -> ValidatedDict:
        base = {
            'name': profile.get('name', ''),
            'game': profile['game'],
            'version': profile['version'],
            'refid': profile['refid'],
            'extid': profile['extid'],
        }

        if profile.get('game') == GameConstants.DDR:
            base.update(self.__format_ddr_profile(profile))
        if profile.get('game') == GameConstants.IIDX:
            base.update(self.__format_iidx_profile(profile))
        if profile.get('game') == GameConstants.JUBEAT:
            base.update(self.__format_jubeat_profile(profile))
        if profile.get('game') == GameConstants.MUSECA:
            base.update(self.__format_museca_profile(profile))
        if profile.get('game') == GameConstants.POPN_MUSIC:
            base.update(self.__format_popn_profile(profile))
        if profile.get('game') == GameConstants.REFLEC_BEAT:
            base.update(self.__format_reflec_profile(profile))
        if profile.get('game') == GameConstants.SDVX:
            base.update(self.__format_sdvx_profile(profile))

        return ValidatedDict(base)
Beispiel #11
0
    def __format_iidx_profile(self, profile: ValidatedDict, exact: bool) -> Dict[str, Any]:
        qpro = profile.get_dict('qpro')

        return {
            'area': profile.get_int('pid', -1),
            'qpro': {
                'head': qpro.get_int('head', -1) if exact else -1,
                'hair': qpro.get_int('hair', -1) if exact else -1,
                'face': qpro.get_int('face', -1) if exact else -1,
                'body': qpro.get_int('body', -1) if exact else -1,
                'hand': qpro.get_int('hand', -1) if exact else -1,
            }
        }
Beispiel #12
0
    def get_settings(self, game: str,
                     userid: UserID) -> Optional[ValidatedDict]:
        """
        Given a game and a user ID, look up game-wide settings as a dictionary.

        It is expected that game classes call this function, and provide a consistent
        game name from version to version, so game settings can be looked up across
        all versions in a game series.

        Parameters:
            game - String identifying a game series.
            userid - Integer identifying a user, as possibly looked up by UserData.

        Returns:
            A dictionary representing game settings stored by a game class, or None
            if there are no settings for this game/user.
        """
        sql = "SELECT data FROM game_settings WHERE game = :game AND userid = :userid"
        cursor = self.execute(sql, {'game': game, 'userid': userid})

        if cursor.rowcount != 1:
            # Settings doesn't exist
            return None

        result = cursor.fetchone()
        return ValidatedDict(self.deserialize(result['data']))
Beispiel #13
0
    def get_item(self, game: str, version: int, catid: int,
                 cattype: str) -> Optional[ValidatedDict]:
        """
        Given a game/userid and catalog id/type, find that catalog entry.

        Note that there can be more than one catalog entry with the same ID and game/userid
        as long as each one is a different type. Essentially, cattype namespaces catalog entry.

        Parameters:
            game - String identifier of the game looking up this entry.
            version - Integer identifier of the version looking up this entry.
            catid - Integer ID, as provided by a game.
            cattype - The type of catalog entry.

        Returns:
            A dictionary as stored by a game class previously, or None if not found.
        """
        sql = (
            "SELECT data FROM catalog "
            "WHERE game = :game AND version = :version AND id = :id AND type = :type"
        )
        cursor = self.execute(sql, {
            'game': game,
            'version': version,
            'id': catid,
            'type': cattype
        })
        if cursor.rowcount != 1:
            # entry doesn't exist
            return None

        result = cursor.fetchone()
        return ValidatedDict(self.deserialize(result['data']))
Beispiel #14
0
    def get_all_time_sensitive_settings(self, game: str, version: int,
                                        name: str) -> List[ValidatedDict]:
        """
        Given a game/version/name, look up all of the time-sensitive settings for this game.

        Parameters:
            game - String identifier of the game we want settings for.
            version - Integer identifying the game version we want settings for.
            name - The name of the setting we are concerned with.

        Returns:
            A list of ValidatedDict of stored settings if there were settings found, or [] otherwise.
            If settings were found, they are guaranteed to include the attributes 'start_time' and
            'end_time' which will both be seconds since the unix epoch (UTC).
        """
        sql = (
            "SELECT data, start_time, end_time FROM time_sensitive_settings WHERE "
            "game = :game AND version = :version AND name = :name")
        cursor = self.execute(sql, {
            'game': game,
            'version': version,
            'name': name
        })
        if cursor.rowcount == 0:
            # setting doesn't exist
            return []

        settings = []
        for result in cursor.fetchall():
            retval = ValidatedDict(self.deserialize(result['data']))
            retval['start_time'] = result['start_time']
            retval['end_time'] = result['end_time']
            settings.append(retval)
        return settings
Beispiel #15
0
    def get_time_sensitive_settings(self, game: str, version: int,
                                    name: str) -> Optional[ValidatedDict]:
        """
        Given a game/version/name, look up the current time-sensitive settings for this game.

        Parameters:
            game - String identifier of the game we want settings for.
            version - Integer identifying the game version we want settings for.
            name - The name of the setting we are concerned with.

        Returns:
            A ValidatedDict of stored settings if the current setting is found, or None otherwise.
            If settings were found, they are guaranteed to include the attributes 'start_time' and
            'end_time' which will both be seconds since the unix epoch (UTC).
        """
        sql = (
            "SELECT data, start_time, end_time FROM time_sensitive_settings WHERE "
            "game = :game AND version = :version AND name = :name AND start_time <= :time AND end_time > :time"
        )
        cursor = self.execute(sql, {
            'game': game,
            'version': version,
            'name': name,
            'time': Time.now()
        })
        if cursor.rowcount != 1:
            # setting doesn't exist
            return None

        result = cursor.fetchone()
        retval = ValidatedDict(self.deserialize(result['data']))
        retval['start_time'] = result['start_time']
        retval['end_time'] = result['end_time']
        return retval
Beispiel #16
0
    def get_achievement(self, game: str, userid: UserID, achievementid: int,
                        achievementtype: str) -> Optional[ValidatedDict]:
        """
        Given a game/userid and achievement id/type, find that achievement.

        Note that there can be more than one achievement with the same ID and game/userid
        as long as each one is a different type. Essentially, achievementtype namespaces achievements.

        Parameters:
            game - String identifier of the game looking up the user.
            userid - Integer user ID, as looked up by one of the above functions.
            achievementid - Integer ID, as provided by a game.
            achievementtype - The type of achievement.

        Returns:
            A dictionary as stored by a game class previously, or None if not found.
        """
        sql = (
            "SELECT data FROM series_achievement "
            "WHERE game = :game AND userid = :userid AND id = :id AND type = :type"
        )
        cursor = self.execute(
            sql, {
                'game': game,
                'userid': userid,
                'id': achievementid,
                'type': achievementtype
            })
        if cursor.rowcount != 1:
            # score doesn't exist
            return None

        result = cursor.fetchone()
        return ValidatedDict(self.deserialize(result['data']))
Beispiel #17
0
    def __init__(
        self,
        game: str,
        version: int,
        songid: int,
        songchart: int,
        name: Optional[str],
        artist: Optional[str],
        genre: Optional[str],
        data: Dict[str, Any],
    ) -> None:
        """
        Initialize the song object.

        Parameters:
            game - The song's game series.
            version - The song's game version.
            songid - The song's ID according to the game.
            songchart - The song's chart number, according to the game.
            name - The name of the song, from the DB.
            artist - The artist of the song, from the DB.
            genre - The genre of the song, from the DB.
            data - Any optional data that a game class uses for a song.
        """
        self.game = game
        self.version = version
        self.id = songid
        self.chart = songchart
        self.name = name
        self.artist = artist
        self.genre = genre
        self.data = ValidatedDict(data)
Beispiel #18
0
    def new_profile_by_refid(self, refid: Optional[str],
                             name: Optional[str]) -> Node:
        """
        Given a RefID and an optional name, create a profile and then return
        a formatted profile node. Similar rationale to get_profile_by_refid.
        """
        if refid is None:
            return None

        if name is None:
            name = 'なし'

        # First, create and save the default profile
        userid = self.data.remote.user.from_refid(self.game, self.version,
                                                  refid)
        defaultprofile = ValidatedDict({
            'name': name,
        })
        self.put_profile(userid, defaultprofile)

        # Now, reload and format the profile, looking up the has old version flag
        profile = self.get_profile(userid)

        oldversion = self.previous_version()
        oldprofile = oldversion.get_profile(userid)
        profile['has_old_version'] = oldprofile is not None

        return self.format_profile(userid, profile)
Beispiel #19
0
    def get_all_play_session_infos(
            self, game: str,
            version: int) -> List[Tuple[UserID, ValidatedDict]]:
        """
        Given a game and version, look up all play session information.

        Parameters:
            game - String identifying a game series.
            version - Integer identifying the version of the game in the series.

        Returns:
            A list of Tuples, consisting of a UserID and the dictionary that would be
            returned for that user if get_play_session_info() was called for that user.
        """
        sql = ("SELECT id, time, userid, data FROM playsession "
               "WHERE game = :game AND version = :version "
               "AND time > :time")
        cursor = self.execute(
            sql,
            {
                'game': game,
                'version': version,
                'time': Time.now() - Time.SECONDS_IN_HOUR,
            },
        )

        ret = []
        for result in cursor.fetchall():
            data = ValidatedDict(self.deserialize(result['data']))
            data['id'] = result['id']
            data['time'] = result['time']
            ret.append((UserID(result['userid']), data))
        return ret
Beispiel #20
0
    def __init__(
        self,
        key: int,
        songid: int,
        songchart: int,
        points: int,
        timestamp: int,
        update: int,
        location: int,
        plays: int,
        data: Dict[str, Any],
    ) -> None:
        """
        Initialize the score object.

        Parameters:
            key - A unique key identifying this exact score.
            songid - The song's ID according to the game.
            songchart - The song's chart number, according to the game.
            points - The points achieved on this song, from the DB.
            timestamp - The timestamp when the record was earned.
            update - The timestamp when the record was last updated (including play count).
            plays - The number of plays the user has recorded for this song and chart.
            location - The ID of the machine that this score was earned on.
            data - Any optional data that a game class recorded with this score.
        """
        self.key = key
        self.id = songid
        self.chart = songchart
        self.points = points
        self.timestamp = timestamp
        self.update = update
        self.location = location
        self.plays = plays
        self.data = ValidatedDict(data)
Beispiel #21
0
    def get_all_player_info(self, userids: List[UserID], limit: Optional[int]=None, allow_remote: bool=False) -> Dict[UserID, Dict[int, Dict[str, Any]]]:
        info: Dict[UserID, Dict[int, Dict[str, Any]]] = {}
        playstats: Dict[UserID, ValidatedDict] = {}

        # Find all versions of the users' profiles, sorted newest to oldest.
        versions = sorted([version for (game, version, name) in self.all_games()], reverse=True)
        for userid in userids:
            info[userid] = {}
            userlimit = limit
            for version in versions:
                if allow_remote:
                    profile = self.data.remote.user.get_profile(self.game, version, userid)
                else:
                    profile = self.data.local.user.get_profile(self.game, version, userid)
                if profile is not None:
                    if userid not in playstats:
                        stats = self.data.local.game.get_settings(self.game, userid)
                        if stats is None:
                            stats = ValidatedDict()
                        playstats[userid] = stats
                    info[userid][version] = self.format_profile(profile, playstats[userid])
                    info[userid][version]['remote'] = RemoteUser.is_remote(userid)
                    # Exit out if we've hit the limit
                    if userlimit is not None:
                        userlimit = userlimit - 1
                        if userlimit == 0:
                            break

        return info
Beispiel #22
0
    def get_settings(self, arcadeid: ArcadeID, game: str, version: int,
                     setting: str) -> Optional[ValidatedDict]:
        """
        Given an arcade and a game/version combo, look up this particular setting.

        Parameters:
            arcadeid - Integer specifying the arcade to delete.
            game - String identifying a game series.
            version - String identifying a game version.
            setting - String identifying the particular setting we're interestsed in.

        Returns:
            A dictionary representing game settings, or None if there are no settings for this game/user.
        """
        sql = "SELECT data FROM arcade_settings WHERE arcadeid = :id AND game = :game AND version = :version AND type = :type"
        cursor = self.execute(sql, {
            'id': arcadeid,
            'game': game,
            'version': version,
            'type': setting
        })

        if cursor.rowcount != 1:
            # Settings doesn't exist
            return None

        result = cursor.fetchone()
        return ValidatedDict(self.deserialize(result['data']))
Beispiel #23
0
 def format_flags(self, settings_dict: ValidatedDict) -> Dict[str, Any]:
     flags = settings_dict.get_int('flags')
     return {
         'grade': (flags & 0x001) != 0,
         'status': (flags & 0x002) != 0,
         'difficulty': (flags & 0x004) != 0,
         'alphabet': (flags & 0x008) != 0,
         'rival_played': (flags & 0x010) != 0,
         'rival_win_lose': (flags & 0x040) != 0,
         'rival_info': (flags & 0x080) != 0,
         'hide_play_count': (flags & 0x100) != 0,
         'disable_song_preview':
         settings_dict.get_int('disable_song_preview') != 0,
         'effector_lock':
         settings_dict.get_int('effector_lock') != 0,
     }
Beispiel #24
0
 def get_server_info(self) -> ValidatedDict:
     resp = self.__exchange_data('', {})
     return ValidatedDict({
         'name': resp['name'],
         'email': resp['email'],
         'versions': resp['versions'],
     })
Beispiel #25
0
    def get_all_profiles(self, game: str,
                         version: int) -> List[Tuple[UserID, ValidatedDict]]:
        """
        Given a game/version, look up all user profiles for that game.

        Parameters:
            game - String identifier of the game we want all user profiles for.
            version - Integer version of the game we want all user profiles for.

        Returns:
            A list of (UserID, dictionaries) previously stored by a game class for each profile.
        """
        sql = (
            "SELECT refid.userid AS userid, refid.refid AS refid, extid.extid AS extid, profile.data AS data "
            "FROM refid, profile, extid "
            "WHERE refid.game = :game AND refid.version = :version "
            "AND refid.refid = profile.refid AND extid.game = refid.game AND extid.userid = refid.userid"
        )
        cursor = self.execute(sql, {'game': game, 'version': version})

        profiles = []
        for result in cursor.fetchall():
            profile = {
                'refid': result['refid'],
                'extid': result['extid'],
                'game': game,
                'version': version,
            }
            profile.update(self.deserialize(result['data']))
            profiles.append((
                UserID(result['userid']),
                ValidatedDict(profile),
            ))

        return profiles
Beispiel #26
0
    def __init__(
        self,
        key: int,
        songid: int,
        songchart: int,
        points: int,
        timestamp: int,
        location: int,
        new_record: bool,
        data: Dict[str, Any],
    ) -> None:
        """
        Initialize the score object.

        Parameters:
            key - A unique key identifying this exact attempt.
            songid - The song's ID according to the game.
            songchart - The song's chart number, according to the game.
            points - The points achieved on this song, from the DB.
            timestamp - The timestamp of the attempt.
            location - The ID of the machine that this score was earned on.
            new_record - Whether this attempt resulted in a new record for this user.
            data - Any optional data that a game class recorded with this score.
        """
        self.key = key
        self.id = songid
        self.chart = songchart
        self.points = points
        self.timestamp = timestamp
        self.location = location
        self.new_record = new_record
        self.data = ValidatedDict(data)
Beispiel #27
0
    def get_link(self, game: str, version: int, userid: UserID, linktype: str, other_userid: UserID) -> Optional[ValidatedDict]:
        """
        Given a game/version/userid and link type + other userid, find that link.

        Note that there can be more than one link with the same user IDs and game/version
        as long as each one is a different type.

        Parameters:
            game - String identifier of the game looking up the user.
            version - Integer version of the game looking up the user.
            userid - Integer user ID, as looked up by one of the above functions.
            linktype - The type of link.
            other_userid - Integer user ID of the account we're linked to.

        Returns:
            A dictionary as stored by a game class previously, or None if not found.
        """
        sql = (
            "SELECT data FROM link WHERE game = :game AND version = :version AND userid = :userid AND type = :type AND other_userid = :other_userid"
        )
        cursor = self.execute(sql, {'game': game, 'version': version, 'userid': userid, 'type': linktype, 'other_userid': other_userid})
        if cursor.rowcount != 1:
            # score doesn't exist
            return None

        result = cursor.fetchone()
        return ValidatedDict(self.deserialize(result['data']))
Beispiel #28
0
    def get_all_lobbies(self, game: str,
                        version: int) -> List[Tuple[UserID, ValidatedDict]]:
        """
        Given a game and version, look up all active lobbies.

        Parameters:
            game - String identifying a game series.
            version - Integer identifying the version of the game in the series.

        Returns:
            A list of dictionaries representing lobby info stored by a game class.
        """
        sql = ("SELECT userid, id, data FROM lobby "
               "WHERE game = :game AND version = :version AND time > :time")
        cursor = self.execute(
            sql,
            {
                'game': game,
                'version': version,
                'time': Time.now() - Time.SECONDS_IN_HOUR,
            },
        )

        ret = []
        for result in cursor.fetchall():
            data = ValidatedDict(self.deserialize(result['data']))
            data['id'] = result['id']
            ret.append((UserID(result['userid']), data))
        return ret
Beispiel #29
0
    def new_profile_by_refid(self, refid: Optional[str], name: Optional[str],
                             pid: Optional[int]) -> ValidatedDict:
        """
        Given a RefID and an optional name, create a profile and then return
        that newly created profile.
        """
        if refid is None:
            return None

        if name is None:
            name = 'なし'
        if pid is None:
            pid = 51

        userid = self.data.remote.user.from_refid(self.game, self.version,
                                                  refid)
        defaultprofile = ValidatedDict({
            'name': name,
            'pid': pid,
            'settings': {
                'flags': 223  # Default to turning on all optional folders
            },
        })
        self.put_profile(userid, defaultprofile)
        profile = self.get_profile(userid)
        return profile
Beispiel #30
0
    def handle_playerdata_usergamedata_send_request(self,
                                                    request: Node) -> Node:
        # Look up user by refid
        refid = request.child_value('data/eaid')
        userid = self.data.remote.user.from_refid(self.game, self.version,
                                                  refid)
        if userid is None:
            root = Node.void('playerdata')
            root.add_child(Node.s32(
                'result', 1))  # Unclear if this is the right thing to do here.
            return root

        # Extract new profile info from old profile
        oldprofile = self.get_profile(userid)
        is_new = False
        if oldprofile is None:
            oldprofile = ValidatedDict()
            is_new = True
        newprofile = self.unformat_profile(userid, request, oldprofile, is_new)

        # Write new profile
        self.put_profile(userid, newprofile)

        # Return success!
        root = Node.void('playerdata')
        root.add_child(Node.s32('result', 0))
        return root