Esempio n. 1
0
    def handle_player23_read_score_request(self, request: Node) -> Node:
        refid = request.child_value('ref_id')

        root = Node.void('player23')

        userid = self.data.remote.user.from_refid(self.game, self.version,
                                                  refid)
        if userid is not None:
            scores = self.data.remote.music.get_scores(self.game, self.version,
                                                       userid)
        else:
            scores = []

        for score in scores:
            # 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: self.GAME_CHART_TYPE_EASY,
                        self.CHART_TYPE_NORMAL: self.GAME_CHART_TYPE_NORMAL,
                        self.CHART_TYPE_HYPER: self.GAME_CHART_TYPE_HYPER,
                        self.CHART_TYPE_EX: self.GAME_CHART_TYPE_EX,
                    }[score.chart]))
            music.add_child(Node.s32('score', points))
            music.add_child(
                Node.u8(
                    'clear_type', {
                        self.PLAY_MEDAL_CIRCLE_FAILED:
                        self.GAME_PLAY_MEDAL_CIRCLE_FAILED,
                        self.PLAY_MEDAL_DIAMOND_FAILED:
                        self.GAME_PLAY_MEDAL_DIAMOND_FAILED,
                        self.PLAY_MEDAL_STAR_FAILED:
                        self.GAME_PLAY_MEDAL_STAR_FAILED,
                        self.PLAY_MEDAL_EASY_CLEAR:
                        self.GAME_PLAY_MEDAL_EASY_CLEAR,
                        self.PLAY_MEDAL_CIRCLE_CLEARED:
                        self.GAME_PLAY_MEDAL_CIRCLE_CLEARED,
                        self.PLAY_MEDAL_DIAMOND_CLEARED:
                        self.GAME_PLAY_MEDAL_DIAMOND_CLEARED,
                        self.PLAY_MEDAL_STAR_CLEARED:
                        self.GAME_PLAY_MEDAL_STAR_CLEARED,
                        self.PLAY_MEDAL_CIRCLE_FULL_COMBO:
                        self.GAME_PLAY_MEDAL_CIRCLE_FULL_COMBO,
                        self.PLAY_MEDAL_DIAMOND_FULL_COMBO:
                        self.GAME_PLAY_MEDAL_DIAMOND_FULL_COMBO,
                        self.PLAY_MEDAL_STAR_FULL_COMBO:
                        self.GAME_PLAY_MEDAL_STAR_FULL_COMBO,
                        self.PLAY_MEDAL_PERFECT: self.GAME_PLAY_MEDAL_PERFECT,
                    }[medal]))
            music.add_child(Node.s16('cnt', score.plays))

        return root
Esempio n. 2
0
    def handle_playerdata_usergamedata_recv_request(self, request: Node) -> Node:
        playerdata = Node.void('playerdata')

        player = Node.void('player')
        playerdata.add_child(player)

        refid = request.child_value('data/refid')
        userid = self.data.remote.user.from_refid(self.game, self.version, refid)
        if userid is not None:
            profile = self.get_profile(userid)
            links = self.data.local.user.get_links(self.game, self.version, userid)
            records = 0

            record = Node.void('record')
            player.add_child(record)

            def acehex(val: int) -> str:
                return hex(val)[2:]

            if profile is None:
                # Just return a default empty node
                record.add_child(Node.string('d', '<NODATA>'))
                records = 1
            else:
                # Figure out what profiles are being requested
                profiletypes = request.child_value('data/recv_csv').split(',')[::2]
                usergamedata = profile.get_dict('usergamedata')
                for ptype in profiletypes:
                    if ptype in usergamedata:
                        records = records + 1

                        if ptype == "COMMON":
                            # Return basic profile options
                            common = usergamedata[ptype]['strdata'].split(b',')
                            common[self.GAME_COMMON_NAME_OFFSET] = profile.get_str('name').encode('ascii')
                            common[self.GAME_COMMON_AREA_OFFSET] = acehex(profile.get_int('area')).encode('ascii')
                            common[self.GAME_COMMON_WEIGHT_DISPLAY_OFFSET] = b'1' if profile.get_bool('workout_mode') else b'0'
                            common[self.GAME_COMMON_WEIGHT_OFFSET] = str(float(profile.get_int('weight')) / 10.0).encode('ascii')
                            common[self.GAME_COMMON_CHARACTER_OFFSET] = acehex(profile.get_int('character')).encode('ascii')
                            usergamedata[ptype]['strdata'] = b','.join(common)
                        if ptype == "OPTION":
                            # Return user settings for frontend
                            option = usergamedata[ptype]['strdata'].split(b',')
                            option[self.GAME_OPTION_FAST_SLOW_OFFSET] = acehex(profile.get_int('early_late')).encode('ascii')
                            option[self.GAME_OPTION_COMBO_POSITION_OFFSET] = acehex(profile.get_int('combo')).encode('ascii')
                            option[self.GAME_OPTION_ARROW_SKIN_OFFSET] = acehex(profile.get_int('arrowskin')).encode('ascii')
                            option[self.GAME_OPTION_GUIDELINE_OFFSET] = acehex(profile.get_int('guidelines')).encode('ascii')
                            option[self.GAME_OPTION_FILTER_OFFSET] = acehex(profile.get_int('filter')).encode('ascii')
                            usergamedata[ptype]['strdata'] = b','.join(option)
                        if ptype == "LAST":
                            # Return the number of calories expended in the last day
                            workouts = self.data.local.user.get_time_based_achievements(
                                self.game,
                                self.version,
                                userid,
                                achievementtype='workout',
                                since=Time.now() - Time.SECONDS_IN_DAY,
                            )
                            total = sum([w.data.get_int('calories') for w in workouts])

                            last = usergamedata[ptype]['strdata'].split(b',')
                            last[self.GAME_LAST_CALORIES_OFFSET] = acehex(total).encode('ascii')
                            usergamedata[ptype]['strdata'] = b','.join(last)
                        if ptype == "RIVAL":
                            # Fill in the DDR code and active status of the three active
                            # rivals.
                            rival = usergamedata[ptype]['strdata'].split(b',')
                            lastdict = profile.get_dict('last')

                            friends: Dict[int, Optional[ValidatedDict]] = {}
                            for link in links:
                                if link.type[:7] != 'friend_':
                                    continue

                                pos = int(link.type[7:])
                                friends[pos] = self.get_profile(link.other_userid)

                            for rivalno in [1, 2, 3]:
                                activeslot = {
                                    1: self.GAME_RIVAL_SLOT_1_ACTIVE_OFFSET,
                                    2: self.GAME_RIVAL_SLOT_2_ACTIVE_OFFSET,
                                    3: self.GAME_RIVAL_SLOT_3_ACTIVE_OFFSET,
                                }[rivalno]

                                whichfriend = lastdict.get_int('rival{}'.format(rivalno)) - 1
                                if whichfriend < 0:
                                    # This rival isn't active
                                    rival[activeslot] = b'0'
                                    continue

                                friendprofile = friends.get(whichfriend)
                                if friendprofile is None:
                                    # This rival doesn't exist
                                    rival[activeslot] = b'0'
                                    continue

                                ddrcodeslot = {
                                    1: self.GAME_RIVAL_SLOT_1_DDRCODE_OFFSET,
                                    2: self.GAME_RIVAL_SLOT_2_DDRCODE_OFFSET,
                                    3: self.GAME_RIVAL_SLOT_3_DDRCODE_OFFSET,
                                }[rivalno]

                                rival[activeslot] = acehex(rivalno).encode('ascii')
                                rival[ddrcodeslot] = acehex(friendprofile.get_int('extid')).encode('ascii')

                            usergamedata[ptype]['strdata'] = b','.join(rival)

                        dnode = Node.string('d', base64.b64encode(usergamedata[ptype]['strdata']).decode('ascii'))
                        dnode.add_child(Node.string('bin1', base64.b64encode(usergamedata[ptype]['bindata']).decode('ascii')))
                        record.add_child(dnode)

            player.add_child(Node.u32('record_num', records))

        playerdata.add_child(Node.s32('result', 0))
        return playerdata
Esempio n. 3
0
    def handle_player_rb5_player_read_rank_5_request(self,
                                                     request: Node) -> Node:
        # This gives us a 6-integer array mapping to user scores for the following:
        # [total score, basic chart score, medium chart score, hard chart score,
        # special chart score]. It also returns the previous rank, but this is
        # not used in-game as far as I can tell.
        current_scores = request.child_value('sc')
        current_minigame_score = request.child_value('mg_sc')

        # First, grab all scores on the network for this version.
        all_scores = self.data.remote.music.get_all_scores(
            self.game, self.version)

        # Now grab all participating users that had scores
        all_users = {userid for (userid, score) in all_scores}

        # Now, group the scores by user, so we can add up the totals, only including
        # scores where the user at least cleared the song.
        scores_by_user = {
            userid: [
                score for (uid, score) in all_scores if uid == userid
                and score.data.get_int('clear_type') >= self.CLEAR_TYPE_CLEARED
            ]
            for userid in all_users
        }

        # Now grab all user profiles for this game
        all_profiles = {
            profile[0]: profile[1]
            for profile in self.data.remote.user.get_all_profiles(
                self.game, self.version)
        }

        # Now, sum up the scores into the five categories that the game expects.
        total_scores = sorted(
            [
                sum([score.points for score in scores])
                for userid, scores in scores_by_user.items()
            ],
            reverse=True,
        )
        basic_scores = sorted(
            [
                sum([
                    score.points
                    for score in scores if score.chart == self.CHART_TYPE_BASIC
                ]) for userid, scores in scores_by_user.items()
            ],
            reverse=True,
        )
        medium_scores = sorted(
            [
                sum([
                    score.points for score in scores
                    if score.chart == self.CHART_TYPE_MEDIUM
                ]) for userid, scores in scores_by_user.items()
            ],
            reverse=True,
        )
        hard_scores = sorted([
            sum([
                score.points
                for score in scores if score.chart == self.CHART_TYPE_HARD
            ]) for userid, scores in scores_by_user.items()
        ], )
        special_scores = sorted(
            [
                sum([
                    score.points for score in scores
                    if score.chart == self.CHART_TYPE_SPECIAL
                ]) for userid, scores in scores_by_user.items()
            ],
            reverse=True,
        )
        minigame_scores = sorted(
            [
                all_profiles.get(userid, ValidatedDict()).get_int('mgsc')
                for userid in all_users
            ],
            reverse=True,
        )

        # Guarantee that a zero score is at the end of every list, so that it makes
        # the algorithm for figuring out place have no edge case.
        total_scores.append(0)
        basic_scores.append(0)
        medium_scores.append(0)
        hard_scores.append(0)
        special_scores.append(0)
        minigame_scores.append(0)

        # Now, figure out where we fit based on the scores sent from the game.
        user_place = [1, 1, 1, 1, 1, 1]
        which_score = [
            total_scores,
            basic_scores,
            medium_scores,
            hard_scores,
            special_scores,
            minigame_scores,
        ]
        earned_scores = current_scores + [current_minigame_score]
        for i in range(len(user_place)):
            earned_score = earned_scores[i]
            scores = which_score[i]
            for score in scores:
                if earned_score >= score:
                    break
                user_place[i] = user_place[i] + 1

        # Separate out minigame rank from scores
        minigame_rank = user_place[-1]
        user_place = user_place[:-1]

        root = Node.void('player')

        # Populate current ranking.
        tbs = Node.void('tbs')
        root.add_child(tbs)
        tbs.add_child(Node.s32_array('new_rank', user_place))
        tbs.add_child(Node.s32_array('old_rank', [-1, -1, -1, -1, -1]))

        # Populate current minigame ranking (LOL).
        mng = Node.void('mng')
        root.add_child(mng)
        mng.add_child(Node.s32('new_rank', minigame_rank))
        mng.add_child(Node.s32('old_rank', -1))

        return root
Esempio n. 4
0
    def handle_game_3_buy_request(self, request: Node) -> Node:
        refid = request.child_value('refid')

        if refid is not None:
            userid = self.data.remote.user.from_refid(self.game, self.version, refid)
        else:
            userid = None

        if userid is not None:
            profile = self.get_profile(userid)
        else:
            profile = None

        if userid is not None and profile is not None:
            # Look up packets and blocks
            packet = profile.get_int('packet')
            block = profile.get_int('block')

            # Add on any additional we earned this round
            packet = packet + (request.child_value('earned_gamecoin_packet') or 0)
            block = block + (request.child_value('earned_gamecoin_block') or 0)

            currency_type = request.child_value('currency_type')
            price = request.child_value('item/price')
            if isinstance(price, list):
                # Sometimes we end up buying more than one item at once
                price = sum(price)

            if currency_type == self.GAME_CURRENCY_PACKETS:
                # This is a valid purchase
                newpacket = packet - price
                if newpacket < 0:
                    result = 1
                else:
                    packet = newpacket
                    result = 0
            elif currency_type == self.GAME_CURRENCY_BLOCKS:
                # This is a valid purchase
                newblock = block - price
                if newblock < 0:
                    result = 1
                else:
                    block = newblock
                    result = 0
            else:
                # Bad currency type
                result = 1

            if result == 0:
                # Transaction is valid, update the profile with new packets and blocks
                profile.replace_int('packet', packet)
                profile.replace_int('block', block)
                self.put_profile(userid, profile)

                # If this was a song unlock, we should mark it as unlocked
                item_type = request.child_value('item/item_type')
                item_id = request.child_value('item/item_id')
                param = request.child_value('item/param')

                if not isinstance(item_type, list):
                    # Sometimes we buy multiple things at once. Make it easier by always assuming this.
                    item_type = [item_type]
                    item_id = [item_id]
                    param = [param]

                for i in range(len(item_type)):
                    self.data.local.user.put_achievement(
                        self.game,
                        self.version,
                        userid,
                        item_id[i],
                        f'item_{item_type[i]}',
                        {
                            'param': param[i],
                        },
                    )

        else:
            # Unclear what to do here, return a bad response
            packet = 0
            block = 0
            result = 1

        game = Node.void('game_3')
        game.add_child(Node.u32('gamecoin_packet', packet))
        game.add_child(Node.u32('gamecoin_block', block))
        game.add_child(Node.s8('result', result))
        return game
Esempio n. 5
0
 def handle_player_read_request(self, request: Node) -> Node:
     refid = request.child_value('rid')
     profile = self.get_profile_by_refid(refid)
     if profile:
         return profile
     return Node.void('player')
Esempio n. 6
0
    def __verify_profile(self, resp: Node) -> int:
        for item in [
                'jubility',
                'jubility_yday',
                'tune_cnt',
                'save_cnt',
                'saved_cnt',
                'fc_cnt',
                'ex_cnt',
                'pf_cnt',
                'clear_cnt',
                'match_cnt',
                'beat_cnt',
                'mynews_cnt',
                'extra_point',
                'is_extra_played',
                'inherit',
                'mtg_entry_cnt',
                'mtg_hold_cnt',
                'mtg_result',
        ]:
            self.assert_path(resp, f"response/gametop/data/player/info/{item}")

        for item in [
                'secret_list',
                'title_list',
                'theme_list',
                'marker_list',
                'parts_list',
                'new/secret_list',
                'new/title_list',
                'new/theme_list',
                'new/marker_list',
        ]:
            self.assert_path(resp, f"response/gametop/data/player/item/{item}")

        for item in [
                'music_id',
                'marker',
                'title',
                'theme',
                'sort',
                'rank_sort',
                'combo_disp',
                'seq_id',
                'parts',
                'category',
                'play_time',
                'expert_option',
                'matching',
                'hazard',
                'hard',
                'shopname',
                'areaname',
        ]:
            self.assert_path(resp, f"response/gametop/data/player/last/{item}")

        # Misc stuff
        self.assert_path(resp, "response/gametop/data/player/session_id")
        self.assert_path(resp, "response/gametop/data/player/event_flag")
        self.assert_path(resp, "response/gametop/data/player/only_now_music")
        self.assert_path(resp, "response/gametop/data/player/lab_edit_seq")
        self.assert_path(resp, "response/gametop/data/player/kac_music")
        self.assert_path(resp, "response/gametop/data/player/rivallist")
        self.assert_path(resp, "response/gametop/data/player/share_music")
        self.assert_path(resp, "response/gametop/data/player/bonus_music")
        self.assert_path(resp, "response/gametop/data/player/history")
        self.assert_path(resp, "response/gametop/data/player/news/checked")
        self.assert_path(resp, "response/gametop/data/player/group/group_id")
        self.assert_path(resp,
                         "response/gametop/data/player/bingo/reward/total")
        self.assert_path(resp,
                         "response/gametop/data/player/bingo/reward/point")
        self.assert_path(
            resp, "response/gametop/data/player/challenge/today/music_id")
        self.assert_path(resp,
                         "response/gametop/data/player/challenge/today/state")
        self.assert_path(
            resp, "response/gametop/data/player/challenge/whim/music_id")
        self.assert_path(resp,
                         "response/gametop/data/player/challenge/whim/state")

        # Profile settings
        self.assert_path(resp, "response/gametop/data/player/name")
        self.assert_path(resp, "response/gametop/data/player/jid")
        self.assert_path(resp, "response/gametop/data/player/refid")

        # Non-player stuff
        self.assert_path(resp, "response/gametop/data/termver")
        self.assert_path(resp, "response/gametop/data/season_etime")
        self.assert_path(resp, "response/gametop/data/white_music_list")
        self.assert_path(resp, "response/gametop/data/open_music_list")

        # Return the jid
        return resp.child_value('gametop/data/player/jid')
Esempio n. 7
0
    def handle_playerdata_request(self, request: Node) -> Optional[Node]:
        method = request.attribute('method')

        if method == 'expire':
            return Node.void('playerdata')

        elif method == 'logout':
            return Node.void('playerdata')

        elif method == 'get':
            modelstring = request.attribute('model')
            refid = request.child_value('ref_id')
            root = self.get_profile_by_refid(
                refid,
                self.NEW_PROFILE_ONLY if modelstring is None else self.OLD_PROFILE_ONLY,
            )
            if root is None:
                root = Node.void('playerdata')
                root.set_attribute('status', str(Status.NO_PROFILE))
            return root

        elif method == 'conversion':
            refid = request.child_value('ref_id')
            name = request.child_value('name')
            chara = request.child_value('chara')
            root = self.new_profile_by_refid(refid, name, chara)
            if root is None:
                root = Node.void('playerdata')
                root.set_attribute('status', str(Status.NO_PROFILE))
            return root

        elif method == 'new':
            refid = request.child_value('ref_id')
            name = request.child_value('name')
            root = self.new_profile_by_refid(refid, name)
            if root is None:
                root = Node.void('playerdata')
                root.set_attribute('status', str(Status.NO_PROFILE))
            return root

        elif method == 'set':
            refid = request.attribute('ref_id')

            root = Node.void('playerdata')
            root.add_child(Node.s8('pref', -1))
            if refid is None:
                return root

            userid = self.data.remote.user.from_refid(self.game, self.version, refid)
            if userid is None:
                return root

            oldprofile = self.get_profile(userid) or ValidatedDict()
            newprofile = self.unformat_profile(userid, request, oldprofile)

            if newprofile is not None:
                self.put_profile(userid, newprofile)
                root.add_child(Node.string('name', newprofile['name']))

            return root

        elif method == 'friend':
            refid = request.attribute('ref_id')
            root = Node.void('playerdata')

            # Look up our own user ID based on the RefID provided.
            userid = self.data.remote.user.from_refid(self.game, self.version, refid)
            if userid is None:
                root.set_attribute('status', str(Status.NO_PROFILE))
                return root

            # Grab the links that we care about.
            links = self.data.local.user.get_links(self.game, self.version, userid)
            profiles: Dict[UserID, ValidatedDict] = {}
            rivals: List[Link] = []
            for link in links:
                if link.type != 'rival':
                    continue

                other_profile = self.get_profile(link.other_userid)
                if other_profile is None:
                    continue
                profiles[link.other_userid] = other_profile
                rivals.append(link)

            for rival in links[:2]:
                rivalid = rival.other_userid
                rivalprofile = profiles[rivalid]
                scores = self.data.remote.music.get_scores(self.game, self.music_version, rivalid)

                # First, output general profile info.
                friend = Node.void('friend')
                root.add_child(friend)

                # This might be for having non-active or non-confirmed friends, but setting to 0 makes the
                # ranking numbers disappear and the player icon show a questionmark.
                friend.add_child(Node.s8('open', 1))

                # Set up some sane defaults.
                friend.add_child(Node.string('name', rivalprofile.get_str('name', 'なし')))
                friend.add_child(Node.string('g_pm_id', ID.format_extid(rivalprofile.get_int('extid'))))
                friend.add_child(Node.s16('chara', rivalprofile.get_int('chara', -1)))

                # Perform hiscore/medal conversion.
                hiscore_array = [0] * int((((self.GAME_MAX_MUSIC_ID * 4) * 17) + 7) / 8)
                clear_medal = [0] * self.GAME_MAX_MUSIC_ID
                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
                    clear_medal[score.id] = clear_medal[score.id] | self.__format_medal_for_score(score)

                    hiscore_index = (score.id * 4) + {
                        self.CHART_TYPE_EASY: self.GAME_CHART_TYPE_EASY_POSITION,
                        self.CHART_TYPE_NORMAL: self.GAME_CHART_TYPE_NORMAL_POSITION,
                        self.CHART_TYPE_HYPER: self.GAME_CHART_TYPE_HYPER_POSITION,
                        self.CHART_TYPE_EX: self.GAME_CHART_TYPE_EX_POSITION,
                    }[score.chart]
                    hiscore_byte_pos = int((hiscore_index * 17) / 8)
                    hiscore_bit_pos = int((hiscore_index * 17) % 8)
                    hiscore_value = points << hiscore_bit_pos
                    hiscore_array[hiscore_byte_pos] = hiscore_array[hiscore_byte_pos] | (hiscore_value & 0xFF)
                    hiscore_array[hiscore_byte_pos + 1] = hiscore_array[hiscore_byte_pos + 1] | ((hiscore_value >> 8) & 0xFF)
                    hiscore_array[hiscore_byte_pos + 2] = hiscore_array[hiscore_byte_pos + 2] | ((hiscore_value >> 16) & 0xFF)

                hiscore = bytes(hiscore_array)
                friend.add_child(Node.u16_array('clear_medal', clear_medal))
                friend.add_child(Node.binary('hiscore', hiscore))

            return root

        # Invalid method
        return None
Esempio n. 8
0
    def handle_lobby_entry_request(self, request: Node) -> Node:
        root = Node.void('lobby')
        root.add_child(Node.s32('interval', 120))
        root.add_child(Node.s32('interval_p', 120))

        # Create a lobby entry for this user
        extid = request.child_value('e/uid')
        userid = self.data.remote.user.from_extid(self.game, self.version,
                                                  extid)
        if userid is not None:
            profile = self.get_profile(userid)
            self.data.local.lobby.put_lobby(
                self.game, self.version, userid, {
                    'mid': request.child_value('e/mid'),
                    'ng': request.child_value('e/ng'),
                    'mopt': request.child_value('e/mopt'),
                    'tid': request.child_value('e/tid'),
                    'tn': request.child_value('e/tn'),
                    'topt': request.child_value('e/topt'),
                    'lid': request.child_value('e/lid'),
                    'sn': request.child_value('e/sn'),
                    'pref': request.child_value('e/pref'),
                    'stg': request.child_value('e/stg'),
                    'pside': request.child_value('e/pside'),
                    'eatime': request.child_value('e/eatime'),
                    'ga': request.child_value('e/ga'),
                    'gp': request.child_value('e/gp'),
                    'la': request.child_value('e/la'),
                })
            lobby = self.data.local.lobby.get_lobby(
                self.game,
                self.version,
                userid,
            )
            root.add_child(Node.s32('eid', lobby.get_int('id')))
            e = Node.void('e')
            root.add_child(e)
            e.add_child(Node.s32('eid', lobby.get_int('id')))
            e.add_child(Node.u16('mid', lobby.get_int('mid')))
            e.add_child(Node.u8('ng', lobby.get_int('ng')))
            e.add_child(Node.s32('uid', profile.get_int('extid')))
            e.add_child(Node.string('pn', profile.get_str('name')))
            e.add_child(Node.s32('uattr', profile.get_int('uattr')))
            e.add_child(Node.s32('mopt', lobby.get_int('mopt')))
            e.add_child(Node.s16('mg', profile.get_int('mg')))
            e.add_child(Node.s32('tid', lobby.get_int('tid')))
            e.add_child(Node.string('tn', lobby.get_str('tn')))
            e.add_child(Node.s32('topt', lobby.get_int('topt')))
            e.add_child(Node.string('lid', lobby.get_str('lid')))
            e.add_child(Node.string('sn', lobby.get_str('sn')))
            e.add_child(Node.u8('pref', lobby.get_int('pref')))
            e.add_child(Node.s8('stg', lobby.get_int('stg')))
            e.add_child(Node.s8('pside', lobby.get_int('pside')))
            e.add_child(Node.s16('eatime', lobby.get_int('eatime')))
            e.add_child(Node.u8_array('ga', lobby.get_int_array('ga', 4)))
            e.add_child(Node.u16('gp', lobby.get_int('gp')))
            e.add_child(Node.u8_array('la', lobby.get_int_array('la', 4)))

        return root
Esempio n. 9
0
    def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict:
        newprofile = copy.deepcopy(oldprofile)

        # Update experience and in-game currencies
        earned_gamecoin_packet = request.child_value('earned_gamecoin_packet')
        if earned_gamecoin_packet is not None:
            newprofile.replace_int('packet', newprofile.get_int('packet') + earned_gamecoin_packet)
        earned_gamecoin_block = request.child_value('earned_gamecoin_block')
        if earned_gamecoin_block is not None:
            newprofile.replace_int('block', newprofile.get_int('block') + earned_gamecoin_block)
        gain_exp = request.child_value('gain_exp')
        if gain_exp is not None:
            newprofile.replace_int('exp', newprofile.get_int('exp') + gain_exp)

        # Miscelaneous stuff
        newprofile.replace_int('m_user_cnt', request.child_value('m_user_cnt'))

        # Update user's unlock status if we aren't force unlocked
        game_config = self.get_game_config()
        if not game_config.get_bool('force_unlock_cards'):
            have_item = request.child_value('have_item')
            if have_item is not None:
                newprofile.replace_int_array('have_item', 512, [1 if x else 0 for x in have_item])
        if not game_config.get_bool('force_unlock_songs'):
            have_note = request.child_value('have_note')
            if have_note is not None:
                newprofile.replace_int_array('have_note', 512, [1 if x else 0 for x in have_note])

        # Grab last information.
        lastdict = newprofile.get_dict('last')
        lastdict.replace_int('headphone', request.child_value('headphone'))
        lastdict.replace_int('hispeed', request.child_value('hispeed'))
        lastdict.replace_int('appeal_id', request.child_value('appeal_id'))
        lastdict.replace_int('frame0', request.child_value('frame0'))
        lastdict.replace_int('frame1', request.child_value('frame1'))
        lastdict.replace_int('frame2', request.child_value('frame2'))
        lastdict.replace_int('frame3', request.child_value('frame3'))
        lastdict.replace_int('frame4', request.child_value('frame4'))
        last = request.child('last')
        if last is not None:
            lastdict.replace_int('music_id', intish(last.attribute('music_id')))
            lastdict.replace_int('music_type', intish(last.attribute('music_type')))
            lastdict.replace_int('sort_type', intish(last.attribute('sort_type')))

        # Save back last information gleaned from results
        newprofile.replace_dict('last', lastdict)

        # Keep track of play statistics
        self.update_play_statistics(userid)

        return newprofile
Esempio n. 10
0
    def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict:
        # For some reason, Pop'n 20 sends us two profile saves, one with 'not done yet'
        # so we only want to process the done yet node. The 'not gameover' save has
        # jubeat collabo stuff set in it, but we don't use that so it doesn't matter.
        if request.child_value('is_not_gameover') == 1:
            return oldprofile

        newprofile = copy.deepcopy(oldprofile)
        newprofile.replace_int('option', request.child_value('option'))
        newprofile.replace_int('chara', request.child_value('chara'))
        newprofile.replace_int('mode', request.child_value('mode'))
        newprofile.replace_int('button', request.child_value('button'))
        newprofile.replace_int('music', request.child_value('music'))
        newprofile.replace_int('sheet', request.child_value('sheet'))
        newprofile.replace_int('last_play_flag', request.child_value('last_play_flag'))
        newprofile.replace_int('category', request.child_value('category'))
        newprofile.replace_int('sub_category', request.child_value('sub_category'))
        newprofile.replace_int('chara_category', request.child_value('chara_category'))
        newprofile.replace_int('medal_and_friend', request.child_value('medal_and_friend'))
        newprofile.replace_int('ep', request.child_value('ep'))
        newprofile.replace_int_array('sp_color_flg', 2, request.child_value('sp_color_flg'))
        newprofile.replace_int('read_news', request.child_value('read_news'))
        newprofile.replace_int('consecutive_days_coupon', request.child_value('consecutive_days_coupon'))
        newprofile.replace_int('tutorial', request.child_value('tutorial'))
        newprofile.replace_int('music_open_pt', request.child_value('music_open_pt'))
        newprofile.replace_int('collabo', request.child_value('collabo'))

        sp_node = request.child('sp_data')
        if sp_node is not None:
            newprofile.replace_int('sp', sp_node.child_value('sp'))

        reflec_node = request.child('reflec_data')
        if reflec_node is not None:
            newprofile.replace_int_array('reflec', 2, reflec_node.child_value('reflec'))

        # Keep track of play statistics
        self.update_play_statistics(userid)

        # Extract player card stuff
        player_card_dict = newprofile.get_dict('player_card')
        player_card_dict.replace_int_array('title', 2, request.child_value('title'))
        player_card_dict.replace_int('frame', request.child_value('frame'))
        player_card_dict.replace_int('base', request.child_value('base'))
        player_card_dict.replace_int_array('seal', 2, request.child_value('seal'))
        player_card_dict.replace_int_array('get_title', 4, request.child_value('get_title'))
        player_card_dict.replace_int('get_frame', request.child_value('get_frame'))
        player_card_dict.replace_int('get_base', request.child_value('get_base'))
        player_card_dict.replace_int_array('get_seal', 2, request.child_value('get_seal'))

        player_card_ex = request.child('player_card_ex')
        if player_card_ex is not None:
            player_card_dict.replace_int('get_title_ex', player_card_ex.child_value('get_title_ex'))
            player_card_dict.replace_int('get_frame_ex', player_card_ex.child_value('get_frame_ex'))
            player_card_dict.replace_int('get_base_ex', player_card_ex.child_value('get_base_ex'))
            player_card_dict.replace_int('get_seal_ex', player_card_ex.child_value('get_seal_ex'))
        newprofile.replace_dict('player_card', player_card_dict)

        # Extract navigate stuff
        navigate_dict = newprofile.get_dict('navigate')
        navigate = request.child('navigate')
        if navigate is not None:
            navigate_dict.replace_int('genre', navigate.child_value('genre'))
            navigate_dict.replace_int('image', navigate.child_value('image'))
            navigate_dict.replace_int('level', navigate.child_value('level'))
            navigate_dict.replace_int('ojama', navigate.child_value('ojama'))
            navigate_dict.replace_int('limit_num', navigate.child_value('limit_num'))
            navigate_dict.replace_int('button', navigate.child_value('button'))
            navigate_dict.replace_int('life', navigate.child_value('life'))
            navigate_dict.replace_int('progress', navigate.child_value('progress'))
        newprofile.replace_dict('navigate', navigate_dict)

        # Extract scores
        for node in request.children:
            if node.name == 'stage':
                songid = node.child_value('no')
                chart = {
                    self.GAME_CHART_TYPE_EASY: self.CHART_TYPE_EASY,
                    self.GAME_CHART_TYPE_NORMAL: self.CHART_TYPE_NORMAL,
                    self.GAME_CHART_TYPE_HYPER: self.CHART_TYPE_HYPER,
                    self.GAME_CHART_TYPE_EX: self.CHART_TYPE_EX,
                }[node.child_value('sheet')]
                medal = (node.child_value('n_data') >> (chart * 4)) & 0x000F
                medal = {
                    self.GAME_PLAY_MEDAL_CIRCLE_FAILED: self.PLAY_MEDAL_CIRCLE_FAILED,
                    self.GAME_PLAY_MEDAL_DIAMOND_FAILED: self.PLAY_MEDAL_DIAMOND_FAILED,
                    self.GAME_PLAY_MEDAL_STAR_FAILED: self.PLAY_MEDAL_STAR_FAILED,
                    self.GAME_PLAY_MEDAL_CIRCLE_CLEARED: self.PLAY_MEDAL_CIRCLE_CLEARED,
                    self.GAME_PLAY_MEDAL_DIAMOND_CLEARED: self.PLAY_MEDAL_DIAMOND_CLEARED,
                    self.GAME_PLAY_MEDAL_STAR_CLEARED: self.PLAY_MEDAL_STAR_CLEARED,
                    self.GAME_PLAY_MEDAL_CIRCLE_FULL_COMBO: self.PLAY_MEDAL_CIRCLE_FULL_COMBO,
                    self.GAME_PLAY_MEDAL_DIAMOND_FULL_COMBO: self.PLAY_MEDAL_DIAMOND_FULL_COMBO,
                    self.GAME_PLAY_MEDAL_STAR_FULL_COMBO: self.PLAY_MEDAL_STAR_FULL_COMBO,
                    self.GAME_PLAY_MEDAL_PERFECT: self.PLAY_MEDAL_PERFECT,
                }[medal]
                points = node.child_value('score')
                self.update_score(userid, songid, chart, points, medal)

        return newprofile
Esempio n. 11
0
    def handle_game_buy_request(self, request: Node) -> Node:
        refid = request.attribute('refid')

        if refid is not None:
            userid = self.data.remote.user.from_refid(self.game, self.version, refid)
        else:
            userid = None

        if userid is not None:
            profile = self.get_profile(userid)
        else:
            profile = None

        if userid is not None and profile is not None:
            # Look up packets and blocks
            packet = profile.get_int('packet')
            block = profile.get_int('block')

            # Add on any additional we earned this round
            packet = packet + (request.child_value('earned_gamecoin_packet') or 0)
            block = block + (request.child_value('earned_gamecoin_block') or 0)

            # Look up the item to get the actual price and currency used
            item = self.data.local.game.get_item(self.game, self.version, request.child_value('catalog_id'), 'song_unlock')
            if item is not None:
                currency_type = request.child_value('currency_type')
                if currency_type == self.GAME_CURRENCY_PACKETS:
                    if 'packets' in item:
                        # This is a valid purchase
                        newpacket = packet - item.get_int('packets')
                        if newpacket < 0:
                            result = 1
                        else:
                            packet = newpacket
                            result = 0
                    else:
                        # Bad transaction
                        result = 1
                elif currency_type == self.GAME_CURRENCY_BLOCKS:
                    if 'blocks' in item:
                        # This is a valid purchase
                        newblock = block - item.get_int('blocks')
                        if newblock < 0:
                            result = 1
                        else:
                            block = newblock
                            result = 0
                    else:
                        # Bad transaction
                        result = 1
                else:
                    # Bad currency type
                    result = 1

                if result == 0:
                    # Transaction is valid, update the profile with new packets and blocks
                    profile.replace_int('packet', packet)
                    profile.replace_int('block', block)
                    self.put_profile(userid, profile)
            else:
                # Bad catalog ID
                result = 1
        else:
            # Unclear what to do here, return a bad response
            packet = 0
            block = 0
            result = 1

        game = Node.void('game')
        game.add_child(Node.u32('gamecoin_packet', packet))
        game.add_child(Node.u32('gamecoin_block', block))
        game.add_child(Node.s8('result', result))
        return game
Esempio n. 12
0
 def handle_pcb23_write_request(self, request: Node) -> Node:
     # Update the name of this cab for admin purposes
     self.update_machine_name(request.child_value('pcb_setting/name'))
     return Node.void('pcb23')
Esempio n. 13
0
    def __verify_profile(self, resp: Node) -> int:
        self.assert_path(resp, "response/gametop/data/info/event_info")
        self.assert_path(resp, "response/gametop/data/info/share_music")
        self.assert_path(resp, "response/gametop/data/info/bonus_music")
        self.assert_path(resp, "response/gametop/data/info/only_now_music")
        self.assert_path(resp, "response/gametop/data/info/fc_challenge/today/music_id")
        self.assert_path(resp, "response/gametop/data/info/white_music_list")
        self.assert_path(resp, "response/gametop/data/info/open_music_list")
        self.assert_path(resp, "response/gametop/data/info/cabinet_survey/id")
        self.assert_path(resp, "response/gametop/data/info/cabinet_survey/status")
        self.assert_path(resp, "response/gametop/data/info/kaitou_bisco/remaining_days")
        self.assert_path(resp, "response/gametop/data/info/league/status")
        self.assert_path(resp, "response/gametop/data/info/bistro/bistro_id")
        self.assert_path(resp, "response/gametop/data/info/jbox/point")
        self.assert_path(resp, "response/gametop/data/info/jbox/emblem/normal/index")
        self.assert_path(resp, "response/gametop/data/info/jbox/emblem/premium/index")

        for item in [
            'jubility',
            'jubility_yday',
            'tune_cnt',
            'save_cnt',
            'saved_cnt',
            'fc_cnt',
            'ex_cnt',
            'clear_cnt',
            'pf_cnt',
            'match_cnt',
            'beat_cnt',
            'mynews_cnt',
            'bonus_tune_points',
            'is_bonus_tune_played',
            'inherit',
            'mtg_entry_cnt',
            'mtg_hold_cnt',
            'mtg_result',
        ]:
            self.assert_path(resp, f"response/gametop/data/player/info/{item}")

        for item in [
            'music_list',
            'secret_list',
            'theme_list',
            'marker_list',
            'title_list',
            'parts_list',
            'emblem_list',
            'new/secret_list',
            'new/theme_list',
            'new/marker_list',
        ]:
            self.assert_path(resp, f"response/gametop/data/player/item/{item}")

        for item in [
            'play_time',
            'shopname',
            'areaname',
            'expert_option',
            'category',
            'sort',
            'music_id',
            'seq_id',
        ]:
            self.assert_path(resp, f"response/gametop/data/player/last/{item}")

        for item in [
            'marker',
            'theme',
            'title',
            'parts',
            'rank_sort',
            'combo_disp',
            'emblem',
            'matching',
            'hazard',
            'hard',
        ]:
            self.assert_path(resp, f"response/gametop/data/player/last/settings/{item}")

        # Misc stuff
        self.assert_path(resp, "response/gametop/data/player/session_id")
        self.assert_path(resp, "response/gametop/data/player/event_flag")

        # Profile settings
        self.assert_path(resp, "response/gametop/data/player/name")
        self.assert_path(resp, "response/gametop/data/player/jid")

        # Required nodes for events and stuff
        self.assert_path(resp, "response/gametop/data/player/history")
        self.assert_path(resp, "response/gametop/data/player/lab_edit_seq")
        self.assert_path(resp, "response/gametop/data/player/event_info")
        self.assert_path(resp, "response/gametop/data/player/cabinet_survey/read_flag")
        self.assert_path(resp, "response/gametop/data/player/kaitou_bisco/read_flag")
        self.assert_path(resp, "response/gametop/data/player/navi/flag")
        self.assert_path(resp, "response/gametop/data/player/fc_challenge/today/music_id")
        self.assert_path(resp, "response/gametop/data/player/fc_challenge/today/state")
        self.assert_path(resp, "response/gametop/data/player/fc_challenge/whim/music_id")
        self.assert_path(resp, "response/gametop/data/player/fc_challenge/whim/state")
        self.assert_path(resp, "response/gametop/data/player/news/checked")
        self.assert_path(resp, "response/gametop/data/player/news/checked_flag")
        self.assert_path(resp, "response/gametop/data/player/rivallist")
        self.assert_path(resp, "response/gametop/data/player/free_first_play/is_available")
        self.assert_path(resp, "response/gametop/data/player/free_first_play/point")
        self.assert_path(resp, "response/gametop/data/player/free_first_play/point_used")
        self.assert_path(resp, "response/gametop/data/player/free_first_play/come_come_jbox/is_valid")
        self.assert_path(resp, "response/gametop/data/player/free_first_play/come_come_jbox/end_time_if_paired")
        self.assert_path(resp, "response/gametop/data/player/jbox/point")
        self.assert_path(resp, "response/gametop/data/player/jbox/emblem/normal/index")
        self.assert_path(resp, "response/gametop/data/player/jbox/emblem/premium/index")
        self.assert_path(resp, "response/gametop/data/player/career/level")
        self.assert_path(resp, "response/gametop/data/player/career/point")
        self.assert_path(resp, "response/gametop/data/player/career/param")
        self.assert_path(resp, "response/gametop/data/player/career/is_unlocked")
        self.assert_path(resp, "response/gametop/data/player/league/is_first_play")
        self.assert_path(resp, "response/gametop/data/player/league/class")
        self.assert_path(resp, "response/gametop/data/player/league/subclass")
        self.assert_path(resp, "response/gametop/data/player/new_music")
        self.assert_path(resp, "response/gametop/data/player/eapass_privilege/emblem_list")
        self.assert_path(resp, "response/gametop/data/player/bonus_music/music")
        self.assert_path(resp, "response/gametop/data/player/bonus_music/event_id")
        self.assert_path(resp, "response/gametop/data/player/bonus_music/till_time")
        self.assert_path(resp, "response/gametop/data/player/bistro/chef/id")
        self.assert_path(resp, "response/gametop/data/player/bistro/carry_over")
        self.assert_path(resp, "response/gametop/data/player/bistro/route_list/route_count")
        self.assert_path(resp, "response/gametop/data/player/bistro/extension")
        self.assert_path(resp, "response/gametop/data/player/gift_list")

        # Return the jid
        return resp.child_value('gametop/data/player/jid')
Esempio n. 14
0
    def handle_shopinfo_regist_request(self, request: Node) -> Node:
        # Update the name of this cab for admin purposes
        self.update_machine_name(request.child_value('shop/name'))

        shopinfo = Node.void('shopinfo')

        data = Node.void('data')
        shopinfo.add_child(data)
        data.add_child(Node.u32('cabid', 1))
        data.add_child(Node.string('locationid', 'nowhere'))
        data.add_child(Node.u8('is_send', 1))
        data.add_child(
            Node.s32_array(
                'white_music_list',
                [
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                    -1,
                ],
            ))
        data.add_child(Node.u8('tax_phase', 1))

        lab = Node.void('lab')
        data.add_child(lab)
        lab.add_child(Node.bool('is_open', False))

        vocaloid_event = Node.void('vocaloid_event')
        data.add_child(vocaloid_event)
        vocaloid_event.add_child(Node.u8('state', 0))
        vocaloid_event.add_child(Node.s32('music_id', 0))

        vocaloid_event2 = Node.void('vocaloid_event2')
        data.add_child(vocaloid_event2)
        vocaloid_event2.add_child(Node.u8('state', 0))
        vocaloid_event2.add_child(Node.s32('music_id', 0))

        # No obnoxious 30 second wait to play.
        matching_off = Node.void('matching_off')
        data.add_child(matching_off)
        matching_off.add_child(Node.bool('is_open', True))

        tenka = Node.void('tenka')
        data.add_child(tenka)
        tenka.add_child(Node.bool('is_participant', False))

        return shopinfo
Esempio n. 15
0
    def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict:
        newprofile = copy.deepcopy(oldprofile)
        play_stats = self.get_play_statistics(userid)

        # Grab last node and accessories so we can make decisions based on type
        last = request.child('last')
        lastdict = newprofile.get_dict('last')
        mode = int(last.attribute('mode'))
        style = int(last.attribute('style'))
        is_dp = style == self.GAME_STYLE_DOUBLE

        # Drill rankings
        title = request.child('title')
        title_gr = request.child('title_gr')
        titledict = newprofile.get_dict('title')
        title_grdict = newprofile.get_dict('title_gr')

        # Groove radar level ups
        gr = request.child('gr')

        # Set the correct values depending on if we're single or double play
        if is_dp:
            play_stats.increment_int('double_plays')
            if gr is not None:
                newprofile.replace_int_array(
                    'gr_d',
                    5,
                    [
                        intish(gr.attribute('gr1')),
                        intish(gr.attribute('gr2')),
                        intish(gr.attribute('gr3')),
                        intish(gr.attribute('gr4')),
                        intish(gr.attribute('gr5')),
                    ],
                )
            if title is not None:
                titledict.replace_int('d', title.value)
                newprofile.replace_dict('title', titledict)
            if title_gr is not None:
                title_grdict.replace_int('d', title.value)
                newprofile.replace_dict('title_gr', title_grdict)
        else:
            play_stats.increment_int('single_plays')
            if gr is not None:
                newprofile.replace_int_array(
                    'gr_s',
                    5,
                    [
                        intish(gr.attribute('gr1')),
                        intish(gr.attribute('gr2')),
                        intish(gr.attribute('gr3')),
                        intish(gr.attribute('gr4')),
                        intish(gr.attribute('gr5')),
                    ],
                )
            if title is not None:
                titledict.replace_int('s', title.value)
                newprofile.replace_dict('title', titledict)
            if title_gr is not None:
                title_grdict.replace_int('s', title.value)
                newprofile.replace_dict('title_gr', title_grdict)
        play_stats.increment_int('cnt_m{}'.format(mode))

        # Update last attributes
        lastdict.replace_int('fri', intish(last.attribute('fri')))
        lastdict.replace_int('style', intish(last.attribute('style')))
        lastdict.replace_int('mode', intish(last.attribute('mode')))
        lastdict.replace_int('cate', intish(last.attribute('cate')))
        lastdict.replace_int('sort', intish(last.attribute('sort')))
        lastdict.replace_int('mid', intish(last.attribute('mid')))
        lastdict.replace_int('mtype', intish(last.attribute('mtype')))
        lastdict.replace_int('cid', intish(last.attribute('cid')))
        lastdict.replace_int('ctype', intish(last.attribute('ctype')))
        lastdict.replace_int('sid', intish(last.attribute('sid')))
        newprofile.replace_dict('last', lastdict)

        # Grab character options
        chara = request.child('chara')
        if chara is not None:
            newprofile.replace_int('chara', intish(chara.attribute('my')))
        newprofile.replace_int_array('chara_opt', 96, request.child_value('chara_opt'))

        # Track event progress
        event = request.child('event')
        if event is not None:
            event_dict = newprofile.get_dict('event')
            event_dict.replace_int('diff_sum', intish(event.attribute('diff_sum')))
            event_dict.replace_int('e_flags', intish(event.attribute('e_flags')))
            event_dict.replace_int('welcome', intish(event.attribute('welcome')))
            newprofile.replace_dict('event', event_dict)

        e_panel = request.child('e_panel')
        if e_panel is not None:
            e_panel_dict = newprofile.get_dict('e_panel')
            e_panel_dict.replace_int('play_id', intish(e_panel.attribute('play_id')))
            e_panel_dict.replace_int_array('cell', 24, e_panel.child_value('cell'))
            e_panel_dict.replace_int_array('panel_state', 6, e_panel.child_value('panel_state'))
            newprofile.replace_dict('e_panel', e_panel_dict)

        e_pix = request.child('e_pix')
        if e_pix is not None:
            e_pix_dict = newprofile.get_dict('e_pix')
            max_distance = e_pix_dict.get_int('max_distance')
            max_planet = e_pix_dict.get_int('max_planet')
            total_distance = e_pix_dict.get_int('total_distance')
            total_planet = e_pix_dict.get_int('total_planet')
            cur_distance = intish(e_pix.attribute('this_distance'))
            cur_planet = intish(e_pix.attribute('this_planet'))
            if cur_distance is not None:
                max_distance = max(max_distance, cur_distance)
                total_distance += cur_distance
            if cur_planet is not None:
                max_planet = max(max_planet, cur_planet)
                total_planet += cur_planet

            e_pix_dict.replace_int('max_distance', max_distance)
            e_pix_dict.replace_int('max_planet', max_planet)
            e_pix_dict.replace_int('total_distance', total_distance)
            e_pix_dict.replace_int('total_planet', total_planet)
            e_pix_dict.replace_int('flags', intish(e_pix.attribute('flags')))
            newprofile.replace_dict('e_pix', e_pix_dict)

        # Options
        opt = request.child('opt')
        if opt is not None:
            # A bug in old versions of AVS returns the wrong number for set
            newprofile.replace_int_array('opt', 16, opt.value[:16])

        # Experience and stars
        exp = request.child_value('exp')
        if exp is not None:
            play_stats.replace_int('exp', play_stats.get_int('exp') + exp)
        star = request.child_value('star')
        if star is not None:
            newprofile.replace_int('star', newprofile.get_int('star') + star)
        star_c = request.child_value('star_c')
        if star_c is not None:
            newprofile.replace_int('star_c', newprofile.get_int('star_c') + exp)

        # Update game flags
        for child in request.children:
            if child.name != 'flag':
                continue
            try:
                value = int(child.attribute('data'))
                offset = int(child.attribute('no'))
            except ValueError:
                continue

            flags = newprofile.get_int_array('flag', 256, [1] * 256)
            if offset < 0 or offset >= len(flags):
                continue
            flags[offset] = value
            newprofile.replace_int_array('flag', 256, flags)

        # Workout mode support
        newweight = -1
        oldweight = newprofile.get_int('weight')
        for child in request.children:
            if child.name != 'weight':
                continue
            newweight = child.value
        if newweight < 0:
            newweight = oldweight

        # Either update or unset the weight depending on the game
        if newweight == 0:
            # Weight is unset or we declined to use this feature, remove from profile
            if 'weight' in newprofile:
                del newprofile['weight']
        else:
            # Weight has been set or previously retrieved, we should save calories
            newprofile.replace_int('weight', newweight)
            total = 0
            for child in request.children:
                if child.name != 'calory':
                    continue
                total += child.value
            self.data.local.user.put_time_based_achievement(
                self.game,
                self.version,
                userid,
                0,
                'workout',
                {
                    'calories': total,
                    'weight': newweight,
                },
            )

        # Look up old friends
        oldfriends: List[Optional[UserID]] = [None] * 10
        links = self.data.local.user.get_links(self.game, self.version, userid)
        for link in links:
            if link.type[:7] != 'friend_':
                continue

            pos = int(link.type[7:])
            oldfriends[pos] = link.other_userid

        # Save any rivals that were added/removed/changed
        newfriends = oldfriends[:]
        for child in request.children:
            if child.name != 'friend':
                continue

            code = int(child.attribute('code'))
            pos = int(child.attribute('pos'))

            if pos >= 0 and pos < 10:
                if code == 0:
                    # We cleared this friend
                    newfriends[pos] = None
                else:
                    # Try looking up the userid
                    newfriends[pos] = self.data.remote.user.from_extid(self.game, self.version, code)

        # Diff the set of links to determine updates
        for i in range(10):
            if newfriends[i] == oldfriends[i]:
                continue

            if newfriends[i] is None:
                # Kill the rival in this location
                self.data.local.user.destroy_link(
                    self.game,
                    self.version,
                    userid,
                    'friend_{}'.format(i),
                    oldfriends[i],
                )
            elif oldfriends[i] is None:
                # Add rival in this location
                self.data.local.user.put_link(
                    self.game,
                    self.version,
                    userid,
                    'friend_{}'.format(i),
                    newfriends[i],
                    {},
                )
            else:
                # Changed the rival here, kill the old one, add the new one
                self.data.local.user.destroy_link(
                    self.game,
                    self.version,
                    userid,
                    'friend_{}'.format(i),
                    oldfriends[i],
                )
                self.data.local.user.put_link(
                    self.game,
                    self.version,
                    userid,
                    'friend_{}'.format(i),
                    newfriends[i],
                    {},
                )

        # Keep track of play statistics
        self.update_play_statistics(userid, play_stats)

        return newprofile
Esempio n. 16
0
    def handle_event_r_get_all_request(self, request: Node) -> Node:
        limit = request.child_value('limit')

        comments = [
            achievement for achievement in self.data.local.user.
            get_all_time_based_achievements(self.game, self.version)
            if achievement[1].type == 'puzzle_comment'
        ]
        comments.sort(key=lambda x: x[1].timestamp, reverse=True)
        statuses = self.data.local.lobby.get_all_play_session_infos(
            self.game, self.version)
        statuses.sort(key=lambda x: x[1]['time'], reverse=True)

        # Cap all comment blocks to the limit
        if limit >= 0:
            comments = comments[:limit]
            statuses = statuses[:limit]

        # Mapping of profiles to userIDs
        uid_mapping = {
            uid: prof
            for (uid, prof) in self.get_any_profiles([c[0] for c in comments] +
                                                     [s[0] for s in statuses])
        }

        # Mapping of location ID to machine name
        lid_mapping: Dict[int, str] = {}

        root = Node.void('event_r')
        root.add_child(Node.s32('time', Time.now()))
        statusnode = Node.void('status')
        root.add_child(statusnode)
        commentnode = Node.void('comment')
        root.add_child(commentnode)

        for (uid, comment) in comments:
            lid = ID.parse_machine_id(comment.data.get_str('lid'))

            # Look up external data for the request
            if lid not in lid_mapping:
                machine = self.get_machine_by_id(lid)
                if machine is not None:
                    lid_mapping[lid] = machine.name
                else:
                    lid_mapping[lid] = ''

            c = Node.void('c')
            commentnode.add_child(c)
            c.add_child(Node.s32('uid', uid_mapping[uid].get_int('extid')))
            c.add_child(Node.string('p_name',
                                    uid_mapping[uid].get_str('name')))
            c.add_child(Node.s32('exp', uid_mapping[uid].get_int('exp')))
            c.add_child(
                Node.s32('customize', comment.data.get_int('customize')))
            c.add_child(Node.s32('tid', comment.data.get_int('teamid')))
            c.add_child(Node.string('t_name',
                                    comment.data.get_str('teamname')))
            c.add_child(Node.string('lid', comment.data.get_str('lid')))
            c.add_child(Node.string('s_name', lid_mapping[lid]))
            c.add_child(Node.s8('pref', comment.data.get_int('prefecture')))
            c.add_child(Node.s32('time', comment.timestamp))
            c.add_child(Node.string('comment',
                                    comment.data.get_str('comment')))
            c.add_child(Node.bool('is_tweet', comment.data.get_bool('tweet')))

        for (uid, status) in statuses:
            lid = ID.parse_machine_id(status.get_str('lid'))

            # Look up external data for the request
            if lid not in lid_mapping:
                machine = self.get_machine_by_id(lid)
                if machine is not None:
                    lid_mapping[lid] = machine.name
                else:
                    lid_mapping[lid] = ''

            s = Node.void('s')
            statusnode.add_child(s)
            s.add_child(Node.s32('uid', uid_mapping[uid].get_int('extid')))
            s.add_child(Node.string('p_name',
                                    uid_mapping[uid].get_str('name')))
            s.add_child(Node.s32('exp', uid_mapping[uid].get_int('exp')))
            s.add_child(Node.s32('customize', status.get_int('customize')))
            s.add_child(
                Node.s32('tid', uid_mapping[uid].get_int('team_id', -1)))
            s.add_child(
                Node.string('t_name',
                            uid_mapping[uid].get_str('team_name', '')))
            s.add_child(Node.string('lid', status.get_str('lid')))
            s.add_child(Node.string('s_name', lid_mapping[lid]))
            s.add_child(Node.s8('pref', status.get_int('prefecture')))
            s.add_child(Node.s32('time', status.get_int('time')))
            s.add_child(Node.s8('status', status.get_int('status')))
            s.add_child(Node.s8('stage', status.get_int('stage')))
            s.add_child(Node.s32('mid', status.get_int('mid')))
            s.add_child(Node.s8('ng', status.get_int('ng')))

        return root
Esempio n. 17
0
 def handle_sysinfo_fan_request(self, request: Node) -> Node:
     sysinfo = Node.void('sysinfo')
     sysinfo.add_child(Node.u8('pref', 51))
     sysinfo.add_child(Node.string('lid', request.child_value('lid')))
     return sysinfo
Esempio n. 18
0
 def handle_lobby_delete_request(self, request: Node) -> Node:
     eid = request.child_value('eid')
     self.data.local.lobby.destroy_lobby(eid)
     return Node.void('lobby')
Esempio n. 19
0
    def unformat_profile(self, userid: UserID, request: Node,
                         oldprofile: ValidatedDict) -> ValidatedDict:
        game_config = self.get_game_config()
        newprofile = copy.deepcopy(oldprofile)

        newprofile.replace_int('lid',
                               ID.parse_machine_id(request.child_value('lid')))
        newprofile.replace_str('name', request.child_value('pdata/base/name'))
        newprofile.replace_int('lvl', request.child_value('pdata/base/lv'))
        newprofile.replace_int('exp', request.child_value('pdata/base/exp'))
        newprofile.replace_int('mg', request.child_value('pdata/base/mg'))
        newprofile.replace_int('ap', request.child_value('pdata/base/ap'))
        newprofile.replace_int('flag', request.child_value('pdata/base/flag'))

        customdict = newprofile.get_dict('custom')
        custom = request.child('pdata/custom')
        if custom:
            customdict.replace_int('bgm_m', custom.child_value('bgm_m'))
            customdict.replace_int('st_f', custom.child_value('st_f'))
            customdict.replace_int('st_bg', custom.child_value('st_bg'))
            customdict.replace_int('st_bg_b', custom.child_value('st_bg_b'))
            customdict.replace_int('eff_e', custom.child_value('eff_e'))
            customdict.replace_int('se_s', custom.child_value('se_s'))
            customdict.replace_int('se_s_v', custom.child_value('se_s_v'))
        newprofile.replace_dict('custom', customdict)

        # Music unlocks and other stuff
        released = request.child('pdata/released')
        if released:
            for child in released.children:
                if child.name != 'info':
                    continue

                item_id = child.child_value('id')
                item_type = child.child_value('type')
                if game_config.get_bool(
                        'force_unlock_songs') and item_type == 0:
                    # Don't save unlocks when we're force unlocking
                    continue

                self.data.local.user.put_achievement(
                    self.game,
                    self.version,
                    userid,
                    item_id,
                    f'item_{item_type}',
                    {},
                )

        # Grab any new records set during this play session. Reflec Beat original only sends
        # the top record back for songs that were played at least once during the session.
        # Note that it sends the top record, so if you play the song twice, it will return
        # only one record. Also, if you get a lower score than a previous try, it will return
        # the previous try. So, we must also look at the battle log for the actual play scores,
        # and combine the data if we can.
        savedrecords: Dict[int, Dict[int, Dict[str, int]]] = {}
        songplays = request.child('pdata/record')
        if songplays:
            for child in songplays.children:
                if child.name != 'rec':
                    continue

                songid = child.child_value('mid')
                chart = child.child_value('ng')

                # These don't get sent with the battle logs, so we try to construct
                # the values here.
                if songid not in savedrecords:
                    savedrecords[songid] = {}
                savedrecords[songid][chart] = {
                    'achievement_rate': child.child_value('ar') * 10,
                    'points': child.child_value('bs'),
                    'combo': child.child_value('mc'),
                    'miss_count': child.child_value('bmc'),
                    'win': child.child_value('win'),
                    'lose': child.child_value('lose'),
                    'draw': child.child_value('draw'),
                }

        # Now, see the actual battles that were played. If we can, unify the data with a record.
        # We only do that when the record achievement rate and score matches the battle achievement
        # rate and score, so we know for a fact that that record was generated by this battle.
        battlelogs = request.child('pdata/blog')
        if battlelogs:
            for child in battlelogs.children:
                if child.name != 'log':
                    continue

                songid = child.child_value('mid')
                chart = child.child_value('ng')

                clear_type = child.child_value('myself/ct')
                achievement_rate = child.child_value('myself/ar') * 10
                points = child.child_value('myself/s')

                clear_type, combo_type = self.__game_to_db_clear_type(
                    clear_type, achievement_rate)

                combo = None
                miss_count = -1
                stats = None

                if songid in savedrecords:
                    if chart in savedrecords[songid]:
                        data = savedrecords[songid][chart]

                        if (data['achievement_rate'] == achievement_rate
                                and data['points'] == points):
                            # This is the same record! Use the stats from it to update our
                            # internal representation.
                            combo = data['combo']
                            miss_count = data['miss_count']
                            stats = {
                                'win': data['win'],
                                'lose': data['lose'],
                                'draw': data['draw'],
                            }

                self.update_score(
                    userid,
                    songid,
                    chart,
                    points,
                    achievement_rate,
                    clear_type,
                    combo_type,
                    miss_count,
                    combo=combo,
                    stats=stats,
                )

        # Keep track of play statistics
        self.update_play_statistics(userid)

        return newprofile
Esempio n. 20
0
    def unformat_profile(self, userid: UserID, request: Node,
                         oldprofile: ValidatedDict) -> ValidatedDict:
        game_config = self.get_game_config()
        newprofile = copy.deepcopy(oldprofile)

        newprofile.replace_int('lid',
                               ID.parse_machine_id(request.child_value('lid')))
        newprofile.replace_str('name', request.child_value('pdata/base/name'))
        newprofile.replace_int('icon',
                               request.child_value('pdata/base/icon_id'))
        newprofile.replace_int('lvl', request.child_value('pdata/base/lv'))
        newprofile.replace_int('exp', request.child_value('pdata/base/exp'))
        newprofile.replace_int('mg', request.child_value('pdata/base/mg'))
        newprofile.replace_int('ap', request.child_value('pdata/base/ap'))
        newprofile.replace_int('pc', request.child_value('pdata/base/pc'))
        newprofile.replace_int('uattr',
                               request.child_value('pdata/base/uattr'))

        customdict = newprofile.get_dict('custom')
        custom = request.child('pdata/custom')
        if custom:
            customdict.replace_int('s_gls', custom.child_value('s_gls'))
            customdict.replace_int('bgm_m', custom.child_value('bgm_m'))
            customdict.replace_int('st_f', custom.child_value('st_f'))
            customdict.replace_int('st_bg', custom.child_value('st_bg'))
            customdict.replace_int('st_bg_b', custom.child_value('st_bg_b'))
            customdict.replace_int('eff_e', custom.child_value('eff_e'))
            customdict.replace_int('se_s', custom.child_value('se_s'))
            customdict.replace_int('se_s_v', custom.child_value('se_s_v'))
            customdict.replace_int('last_music_id',
                                   custom.child_value('last_music_id'))
            customdict.replace_int('last_note_grade',
                                   custom.child_value('last_note_grade'))
            customdict.replace_int('sort_type',
                                   custom.child_value('sort_type'))
            customdict.replace_int('narrowdown_type',
                                   custom.child_value('narrowdown_type'))
            customdict.replace_bool(
                'is_begginer', custom.child_value(
                    'is_begginer'))  # Yes, this is spelled right
            customdict.replace_bool('is_tut', custom.child_value('is_tut'))
            customdict.replace_int_array('symbol_chat_0', 6,
                                         custom.child_value('symbol_chat_0'))
            customdict.replace_int_array('symbol_chat_1', 6,
                                         custom.child_value('symbol_chat_1'))
            customdict.replace_int('gauge_style',
                                   custom.child_value('gauge_style'))
            customdict.replace_int('obj_shade',
                                   custom.child_value('obj_shade'))
            customdict.replace_int('obj_size', custom.child_value('obj_size'))
            customdict.replace_int_array('byword', 2,
                                         custom.child_value('byword'))
            customdict.replace_bool_array('is_auto_byword', 2,
                                          custom.child_value('is_auto_byword'))
            customdict.replace_bool('is_tweet', custom.child_value('is_tweet'))
            customdict.replace_bool('is_link_twitter',
                                    custom.child_value('is_link_twitter'))
            customdict.replace_int('mrec_type',
                                   custom.child_value('mrec_type'))
            customdict.replace_int('card_disp_type',
                                   custom.child_value('card_disp_type'))
            customdict.replace_int('tab_sel', custom.child_value('tab_sel'))
            customdict.replace_int_array('hidden_param', 20,
                                         custom.child_value('hidden_param'))
        newprofile.replace_dict('custom', customdict)

        # Music unlocks and other stuff
        released = request.child('pdata/released')
        if released:
            for child in released.children:
                if child.name != 'info':
                    continue

                item_id = child.child_value('id')
                item_type = child.child_value('type')
                param = child.child_value('param')
                if game_config.get_bool(
                        'force_unlock_songs') and item_type == 0:
                    # Don't save unlocks when we're force unlocking
                    continue

                self.data.local.user.put_achievement(
                    self.game,
                    self.version,
                    userid,
                    item_id,
                    'item_{}'.format(item_type),
                    {
                        'param': param,
                    },
                )

        # Grab any new records set during this play session. Reflec Beat Limelight only sends
        # the top record back for songs that were played at least once during the session.
        # Note that it sends the top record, so if you play the song twice, it will return
        # only one record. Also, if you get a lower score than a previous try, it will return
        # the previous try. So, we must also look at the battle log for the actual play scores,
        # and combine the data if we can.
        savedrecords: Dict[int, Dict[int, Dict[str, int]]] = {}
        songplays = request.child('pdata/record')
        if songplays:
            for child in songplays.children:
                if child.name != 'rec':
                    continue

                songid = child.child_value('mid')
                chart = child.child_value('ng')

                # These don't get sent with the battle logs, so we try to construct
                # the values here.
                if songid not in savedrecords:
                    savedrecords[songid] = {}
                savedrecords[songid][chart] = {
                    'achievement_rate': child.child_value('mrec_0/ar') * 10,
                    'points': child.child_value('mrec_0/bs'),
                    'combo': child.child_value('mrec_0/mc'),
                    'miss_count': child.child_value('mrec_0/bmc'),
                    'win': child.child_value('mrec_0/win'),
                    'lose': child.child_value('mrec_0/lose'),
                    'draw': child.child_value('mrec_0/draw'),
                    'earned_points': child.child_value('point'),
                }

        # Now, see the actual battles that were played. If we can, unify the data with a record.
        # We only do that when the record achievement rate and score matches the battle achievement
        # rate and score, so we know for a fact that that record was generated by this battle.
        battlelogs = request.child('pdata/blog')
        if battlelogs:
            for child in battlelogs.children:
                if child.name != 'log':
                    continue

                songid = child.child_value('mid')
                chart = child.child_value('ng')

                clear_type = child.child_value('myself/ct')
                achievement_rate = child.child_value('myself/ar') * 10
                points = child.child_value('myself/s')

                clear_type, combo_type = self.__game_to_db_clear_type(
                    clear_type)

                combo = None
                miss_count = -1
                stats = None

                if songid in savedrecords:
                    if chart in savedrecords[songid]:
                        data = savedrecords[songid][chart]

                        if (data['achievement_rate'] == achievement_rate
                                and data['points'] == points):
                            # This is the same record! Use the stats from it to update our
                            # internal representation.
                            combo = data['combo']
                            miss_count = data['miss_count']
                            stats = {
                                'win': data['win'],
                                'lose': data['lose'],
                                'draw': data['draw'],
                                'earned_points': data['earned_points'],
                            }

                self.update_score(
                    userid,
                    songid,
                    chart,
                    points,
                    achievement_rate,
                    clear_type,
                    combo_type,
                    miss_count,
                    combo=combo,
                    stats=stats,
                )

        # Keep track of glass points so unlocks work
        glass = request.child('pdata/glass')
        if glass:
            for child in glass.children:
                if child.name != 'g':
                    continue

                gid = child.child_value('id')
                exp = child.child_value('exp')
                self.data.local.user.put_achievement(
                    self.game,
                    self.version,
                    userid,
                    gid,
                    'glass',
                    {
                        'exp': exp,
                    },
                )

        # Keep track of favorite music selections
        fav_music_slot = request.child('pdata/fav_music_slot')
        if fav_music_slot:
            for child in fav_music_slot.children:
                if child.name != 'slot':
                    continue

                slot_id = child.child_value('slot_id')
                music_id = child.child_value('music_id')
                if music_id == -1:
                    # Delete this favorite
                    self.data.local.user.destroy_achievement(
                        self.game,
                        self.version,
                        userid,
                        slot_id,
                        'music',
                    )
                else:
                    # Add/update this favorite
                    self.data.local.user.put_achievement(
                        self.game,
                        self.version,
                        userid,
                        slot_id,
                        'music',
                        {
                            'music_id': music_id,
                        },
                    )

        # Keep track of play statistics
        self.update_play_statistics(userid)

        return newprofile
Esempio n. 21
0
    def __verify_profile(self, resp: Node) -> int:
        self.assert_path(resp, "response/gametop/data/info/event_info")
        self.assert_path(resp, "response/gametop/data/info/share_music")
        self.assert_path(resp, "response/gametop/data/info/bonus_music")
        self.assert_path(resp, "response/gametop/data/info/white_music_list")
        self.assert_path(resp, "response/gametop/data/info/white_marker_list")
        self.assert_path(resp, "response/gametop/data/info/white_theme_list")
        self.assert_path(resp, "response/gametop/data/info/open_music_list")
        self.assert_path(resp, "response/gametop/data/info/shareable_music_list")
        self.assert_path(resp, "response/gametop/data/info/jbox/point")
        self.assert_path(resp, "response/gametop/data/info/jbox/emblem/normal/index")
        self.assert_path(resp, "response/gametop/data/info/jbox/emblem/premium/index")
        self.assert_path(resp, "response/gametop/data/info/born/status")
        self.assert_path(resp, "response/gametop/data/info/born/year")
        self.assert_path(resp, "response/gametop/data/info/digdig/stage_list")
        self.assert_path(resp, "response/gametop/data/info/collection/rating_s")
        self.assert_path(resp, "response/gametop/data/info/generic_dig/map_list")

        for item in [
            'jubility',
            'jubility_yday',
            'tune_cnt',
            'save_cnt',
            'saved_cnt',
            'fc_cnt',
            'ex_cnt',
            'clear_cnt',
            'match_cnt',
            'beat_cnt',
            'mynews_cnt',
            'bonus_tune_points',
            'is_bonus_tune_played',
            'inherit',
            'mtg_entry_cnt',
            'mtg_hold_cnt',
            'mtg_result',
        ]:
            self.assert_path(resp, "response/gametop/data/player/info/{}".format(item))

        for item in [
            'music_list',
            'secret_list',
            'theme_list',
            'marker_list',
            'title_list',
            'parts_list',
            'emblem_list',
            'new/secret_list',
            'new/theme_list',
            'new/marker_list',
        ]:
            self.assert_path(resp, "response/gametop/data/player/item/{}".format(item))

        for item in [
            'play_time',
            'shopname',
            'areaname',
            'expert_option',
            'category',
            'sort',
            'music_id',
            'seq_id',
        ]:
            self.assert_path(resp, "response/gametop/data/player/last/{}".format(item))

        for item in [
            'marker',
            'theme',
            'title',
            'parts',
            'rank_sort',
            'combo_disp',
            'emblem',
            'matching',
            'hazard',
            'hard',
        ]:
            self.assert_path(resp, "response/gametop/data/player/last/settings/{}".format(item))

        # Misc stuff
        self.assert_path(resp, "response/gametop/data/player/session_id")
        self.assert_path(resp, "response/gametop/data/player/event_flag")

        # Profile settings
        self.assert_path(resp, "response/gametop/data/player/name")
        self.assert_path(resp, "response/gametop/data/player/jid")

        # Required nodes for events and stuff
        self.assert_path(resp, "response/gametop/data/player/history")
        self.assert_path(resp, "response/gametop/data/player/lab_edit_seq")
        self.assert_path(resp, "response/gametop/data/player/event_info")
        self.assert_path(resp, "response/gametop/data/player/navi/flag")
        self.assert_path(resp, "response/gametop/data/player/fc_challenge/today/music_id")
        self.assert_path(resp, "response/gametop/data/player/fc_challenge/today/state")
        self.assert_path(resp, "response/gametop/data/player/fc_challenge/whim/music_id")
        self.assert_path(resp, "response/gametop/data/player/fc_challenge/whim/state")
        self.assert_path(resp, "response/gametop/data/player/news/checked")
        self.assert_path(resp, "response/gametop/data/player/news/checked_flag")
        self.assert_path(resp, "response/gametop/data/player/rivallist")
        self.assert_path(resp, "response/gametop/data/player/free_first_play/is_available")
        self.assert_path(resp, "response/gametop/data/player/jbox/point")
        self.assert_path(resp, "response/gametop/data/player/jbox/emblem/normal/index")
        self.assert_path(resp, "response/gametop/data/player/jbox/emblem/premium/index")
        self.assert_path(resp, "response/gametop/data/player/new_music")
        self.assert_path(resp, "response/gametop/data/player/gift_list")
        self.assert_path(resp, "response/gametop/data/player/born/status")
        self.assert_path(resp, "response/gametop/data/player/born/year")
        self.assert_path(resp, "response/gametop/data/player/generic_dig/map_list")
        self.assert_path(resp, "response/gametop/data/player/unlock/main/stage_list")
        self.assert_path(resp, "response/gametop/data/player/digdig/flag")
        self.assert_path(resp, "response/gametop/data/player/digdig/main/stage/point")
        self.assert_path(resp, "response/gametop/data/player/digdig/main/stage/param")
        self.assert_path(resp, "response/gametop/data/player/digdig/eternal/ratio")
        self.assert_path(resp, "response/gametop/data/player/digdig/eternal/used_point")
        self.assert_path(resp, "response/gametop/data/player/digdig/eternal/point")
        self.assert_path(resp, "response/gametop/data/player/digdig/eternal/excavated_point")
        self.assert_path(resp, "response/gametop/data/player/digdig/eternal/cube/state")
        self.assert_path(resp, "response/gametop/data/player/digdig/eternal/cube/item/kind")
        self.assert_path(resp, "response/gametop/data/player/digdig/eternal/cube/item/value")
        self.assert_path(resp, "response/gametop/data/player/digdig/eternal/cube/norma/till_time")
        self.assert_path(resp, "response/gametop/data/player/digdig/eternal/cube/norma/kind")
        self.assert_path(resp, "response/gametop/data/player/digdig/eternal/cube/norma/value")
        self.assert_path(resp, "response/gametop/data/player/digdig/eternal/cube/norma/param")

        # Return the jid
        return resp.child_value('gametop/data/player/jid')
Esempio n. 22
0
    def unformat_profile(self, userid: UserID, request: Node,
                         oldprofile: ValidatedDict) -> ValidatedDict:
        newprofile = copy.deepcopy(oldprofile)

        # Update blaster energy and in-game currencies
        earned_gamecoin_packet = request.child_value('earned_gamecoin_packet')
        if earned_gamecoin_packet is not None:
            newprofile.replace_int(
                'packet',
                newprofile.get_int('packet') + earned_gamecoin_packet)
        earned_gamecoin_block = request.child_value('earned_gamecoin_block')
        if earned_gamecoin_block is not None:
            newprofile.replace_int(
                'block',
                newprofile.get_int('block') + earned_gamecoin_block)
        earned_blaster_energy = request.child_value('earned_blaster_energy')
        if earned_blaster_energy is not None:
            newprofile.replace_int(
                'blaster_energy',
                newprofile.get_int('blaster_energy') + earned_blaster_energy)

        # Miscelaneous stuff
        newprofile.replace_int('blaster_count',
                               request.child_value('blaster_count'))
        newprofile.replace_int('skill_name_id',
                               request.child_value('skill_name_id'))
        newprofile.replace_int_array('hidden_param', 20,
                                     request.child_value('hidden_param'))

        # Update user's unlock status if we aren't force unlocked
        game_config = self.get_game_config()

        if request.child('item') is not None:
            for child in request.child('item').children:
                if child.name != 'info':
                    continue

                item_id = child.child_value('id')
                item_type = child.child_value('type')
                param = child.child_value('param')
                diff_param = child.child_value('diff_param')

                if game_config.get_bool(
                        'force_unlock_songs'
                ) and item_type == self.GAME_CATALOG_TYPE_SONG:
                    # Don't save back songs, because they were force unlocked
                    continue

                if diff_param is not None:
                    paramvals = {
                        'diff_param': diff_param,
                        'param': param,
                    }
                else:
                    paramvals = {
                        'param': param,
                    }

                self.data.local.user.put_achievement(
                    self.game,
                    self.version,
                    userid,
                    item_id,
                    f'item_{item_type}',
                    paramvals,
                )

        # Grab last information.
        lastdict = newprofile.get_dict('last')
        lastdict.replace_int('headphone', request.child_value('headphone'))
        lastdict.replace_int('appeal_id', request.child_value('appeal_id'))
        lastdict.replace_int('comment_id', request.child_value('comment_id'))
        lastdict.replace_int('music_id', request.child_value('music_id'))
        lastdict.replace_int('music_type', request.child_value('music_type'))
        lastdict.replace_int('sort_type', request.child_value('sort_type'))
        lastdict.replace_int('narrow_down', request.child_value('narrow_down'))
        lastdict.replace_int('gauge_option',
                             request.child_value('gauge_option'))

        # Save back last information gleaned from results
        newprofile.replace_dict('last', lastdict)

        # Keep track of play statistics
        self.update_play_statistics(userid)

        return newprofile
Esempio n. 23
0
    def __handle_usersave(self, userid: Optional[UserID], requestdata: Node, response: Node) -> None:
        if userid is None:
            # the game sends us empty user ID strings when a guest is playing.
            # Return early so it doesn't wait a minute and a half to show the
            # results screen.
            return

        if requestdata.child_value('isgameover'):
            style = int(requestdata.child_value('playstyle'))
            is_dp = style == self.GAME_STYLE_DOUBLE

            # We don't save anything for gameover requests, since we
            # already saved scores on individual ones. So, just use this
            # as a spot to bump play counts and such
            play_stats = self.get_play_statistics(userid)
            if is_dp:
                play_stats.increment_int('double_plays')
            else:
                play_stats.increment_int('single_plays')
            self.update_play_statistics(userid, play_stats)

            # Now is a good time to check if we have workout mode enabled,
            # and if so, store the calories earned for this set.
            profile = self.get_profile(userid)
            enabled = profile.get_bool('workout_mode')
            weight = profile.get_int('weight')

            if enabled and weight > 0:
                # We enabled weight display, find the calories and save them
                total = 0
                for child in requestdata.children:
                    if child.name != 'note':
                        continue

                    total = total + (child.child_value('calorie') or 0)

                self.data.local.user.put_time_based_achievement(
                    self.game,
                    self.version,
                    userid,
                    0,
                    'workout',
                    {
                        'calories': total,
                        'weight': weight,
                    },
                )

            # Find any event updates
            for child in requestdata.children:
                if child.name != 'event':
                    continue

                # Skip empty events or events we don't support
                eventid = child.child_value('eventid')
                eventtype = child.child_value('eventtype')
                if eventid == 0 or eventtype == 0:
                    continue

                # Save data to replay to the client later
                completed = child.child_value('comptime') != 0
                progress = child.child_value('savedata')

                self.data.local.user.put_achievement(
                    self.game,
                    self.version,
                    userid,
                    eventid,
                    str(eventtype),
                    {
                        'completed': completed,
                        'progress': progress,
                    },
                )

            return

        # Find the highest stagenum played
        score = None
        stagenum = 0
        for child in requestdata.children:
            if child.name != 'note':
                continue

            if child.child_value('stagenum') > stagenum:
                score = child
                stagenum = child.child_value('stagenum')

        if score is None:
            raise Exception('Couldn\'t find newest score to save!')

        songid = score.child_value('mcode')
        chart = self.game_to_db_chart(score.child_value('notetype'))
        rank = self.game_to_db_rank(score.child_value('rank'))
        halo = self.game_to_db_halo(score.child_value('clearkind'))
        points = score.child_value('score')
        combo = score.child_value('maxcombo')
        ghost = score.child_value('ghost')
        self.update_score(
            userid,
            songid,
            chart,
            points,
            rank,
            halo,
            combo,
            ghost=ghost,
        )
Esempio n. 24
0
    def unformat_profile(self, userid: UserID, request: Node,
                         oldprofile: ValidatedDict) -> ValidatedDict:
        game_config = self.get_game_config()
        newprofile = copy.deepcopy(oldprofile)

        # Save base player profile info
        newprofile.replace_int(
            'lid',
            ID.parse_machine_id(request.child_value('pdata/account/lid')))
        newprofile.replace_str('name', request.child_value('pdata/base/name'))
        newprofile.replace_int('mg', request.child_value('pdata/base/mg'))
        newprofile.replace_int('ap', request.child_value('pdata/base/ap'))
        newprofile.replace_int('uattr',
                               request.child_value('pdata/base/uattr'))
        newprofile.replace_int('money',
                               request.child_value('pdata/base/money'))
        newprofile.replace_int('class',
                               request.child_value('pdata/base/class'))
        newprofile.replace_int('class_ar',
                               request.child_value('pdata/base/class_ar'))
        newprofile.replace_int('skill_point',
                               request.child_value('pdata/base/skill_point'))
        newprofile.replace_int('mgid',
                               request.child_value('pdata/minigame/mgid'))
        newprofile.replace_int('mgsc',
                               request.child_value('pdata/minigame/sc'))
        newprofile.replace_int_array(
            'favorites', 30, request.child_value('pdata/mylist/list/mlst'))

        # Save player config
        configdict = newprofile.get_dict('config')
        config = request.child('pdata/config')
        if config:
            configdict.replace_int('msel_bgm', config.child_value('msel_bgm'))
            configdict.replace_int('narrowdown_type',
                                   config.child_value('narrowdown_type'))
            configdict.replace_int('icon_id', config.child_value('icon_id'))
            configdict.replace_int('byword_0', config.child_value('byword_0'))
            configdict.replace_int('byword_1', config.child_value('byword_1'))
            configdict.replace_bool('is_auto_byword_0',
                                    config.child_value('is_auto_byword_0'))
            configdict.replace_bool('is_auto_byword_1',
                                    config.child_value('is_auto_byword_1'))
            configdict.replace_int('mrec_type',
                                   config.child_value('mrec_type'))
            configdict.replace_int('tab_sel', config.child_value('tab_sel'))
            configdict.replace_int('card_disp',
                                   config.child_value('card_disp'))
            configdict.replace_int('score_tab_disp',
                                   config.child_value('score_tab_disp'))
            configdict.replace_int('last_music_id',
                                   config.child_value('last_music_id'))
            configdict.replace_int('last_note_grade',
                                   config.child_value('last_note_grade'))
            configdict.replace_int('sort_type',
                                   config.child_value('sort_type'))
            configdict.replace_int('rival_panel_type',
                                   config.child_value('rival_panel_type'))
            configdict.replace_int('random_entry_work',
                                   config.child_value('random_entry_work'))
            configdict.replace_int('custom_folder_work',
                                   config.child_value('custom_folder_work'))
            configdict.replace_int('folder_type',
                                   config.child_value('folder_type'))
            configdict.replace_int('folder_lamp_type',
                                   config.child_value('folder_lamp_type'))
            configdict.replace_bool('is_tweet', config.child_value('is_tweet'))
            configdict.replace_bool('is_link_twitter',
                                    config.child_value('is_link_twitter'))
        newprofile.replace_dict('config', configdict)

        # Save player custom settings
        customdict = newprofile.get_dict('custom')
        custom = request.child('pdata/custom')
        if custom:
            customdict.replace_int('st_shot', custom.child_value('st_shot'))
            customdict.replace_int('st_frame', custom.child_value('st_frame'))
            customdict.replace_int('st_expl', custom.child_value('st_expl'))
            customdict.replace_int('st_bg', custom.child_value('st_bg'))
            customdict.replace_int('st_shot_vol',
                                   custom.child_value('st_shot_vol'))
            customdict.replace_int('st_bg_bri',
                                   custom.child_value('st_bg_bri'))
            customdict.replace_int('st_obj_size',
                                   custom.child_value('st_obj_size'))
            customdict.replace_int('st_jr_gauge',
                                   custom.child_value('st_jr_gauge'))
            customdict.replace_int('st_clr_gauge',
                                   custom.child_value('st_clr_gauge'))
            customdict.replace_int('st_gr_gauge_type',
                                   custom.child_value('st_gr_gauge_type'))
            customdict.replace_int('voice_message_set',
                                   custom.child_value('voice_message_set'))
            customdict.replace_int('same_time_note_disp',
                                   custom.child_value('same_time_note_disp'))
            customdict.replace_int('st_score_disp_type',
                                   custom.child_value('st_score_disp_type'))
            customdict.replace_int('st_bonus_type',
                                   custom.child_value('st_bonus_type'))
            customdict.replace_int('st_rivalnote_type',
                                   custom.child_value('st_rivalnote_type'))
            customdict.replace_int('st_topassist_type',
                                   custom.child_value('st_topassist_type'))
            customdict.replace_int('high_speed',
                                   custom.child_value('high_speed'))
            customdict.replace_int('st_hazard',
                                   custom.child_value('st_hazard'))
            customdict.replace_int('st_clr_cond',
                                   custom.child_value('st_clr_cond'))
            customdict.replace_int('voice_message_volume',
                                   custom.child_value('voice_message_volume'))
        newprofile.replace_dict('custom', customdict)

        # Save player parameter info
        params = request.child('pdata/player_param')
        if params:
            for child in params.children:
                if child.name != 'item':
                    continue

                item_type = child.child_value('type')
                bank = child.child_value('bank')
                data = child.child_value('data')
                while len(data) < 256:
                    data.append(0)
                self.data.local.user.put_achievement(
                    self.game,
                    self.version,
                    userid,
                    bank,
                    f'player_param_{item_type}',
                    {
                        'data': data,
                    },
                )

        # Save player episode info
        episode = request.child('pdata/episode')
        if episode:
            for child in episode.children:
                if child.name != 'info':
                    continue

                # I assume this is copypasta, but I want to be sure
                extid = child.child_value('user_id')
                if extid != newprofile.get_int('extid'):
                    raise Exception(
                        f'Unexpected user ID, got {extid} expecting {newprofile.get_int("extid")}'
                    )

                episode_type = child.child_value('type')
                episode_value0 = child.child_value('value0')
                episode_value1 = child.child_value('value1')
                episode_text = child.child_value('text')
                episode_time = child.child_value('time')
                self.data.local.user.put_achievement(
                    self.game,
                    self.version,
                    userid,
                    episode_type,
                    'episode',
                    {
                        'value0': episode_value0,
                        'value1': episode_value1,
                        'text': episode_text,
                        'time': episode_time,
                    },
                )

        # Save released info
        released = request.child('pdata/released')
        if released:
            for child in released.children:
                if child.name != 'info':
                    continue

                item_id = child.child_value('id')
                item_type = child.child_value('type')
                param = child.child_value('param')
                time = child.child_value('insert_time') or Time.now()
                if game_config.get_bool(
                        'force_unlock_songs') and item_type == 0:
                    # Don't save unlocks when we're force unlocking
                    continue

                self.data.local.user.put_achievement(
                    self.game,
                    self.version,
                    userid,
                    item_id,
                    f'item_{item_type}',
                    {
                        'param': param,
                        'time': time,
                    },
                )

        # Save announce info
        announce = request.child('pdata/announce')
        if announce:
            for child in announce.children:
                if child.name != 'info':
                    continue

                announce_id = child.child_value('id')
                announce_type = child.child_value('type')
                param = child.child_value('param')
                need = child.child_value('bneedannounce')
                self.data.local.user.put_achievement(
                    self.game,
                    self.version,
                    userid,
                    announce_id,
                    f'announcement_{announce_type}',
                    {
                        'param': param,
                        'need': need,
                    },
                )

        # Grab any new records set during this play session
        songplays = request.child('pdata/stglog')
        if songplays:
            for child in songplays.children:
                if child.name != 'log':
                    continue

                songid = child.child_value('mid')
                chart = child.child_value('ng')
                clear_type = child.child_value('ct')
                if songid == 0 and chart == 0 and clear_type == -1:
                    # Dummy song save during profile create
                    continue

                points = child.child_value('sc')
                achievement_rate = child.child_value('ar')
                param = child.child_value('param')
                miss_count = child.child_value('jt_ms')
                k_flag = child.child_value('k_flag')

                # Param is some random bits along with the combo type
                combo_type = param & 0x3
                param = param ^ combo_type

                clear_type = self._game_to_db_clear_type(clear_type)
                combo_type = self._game_to_db_combo_type(
                    combo_type, miss_count)
                self.update_score(
                    userid,
                    songid,
                    chart,
                    points,
                    achievement_rate,
                    clear_type,
                    combo_type,
                    miss_count,
                    param=param,
                    kflag=k_flag,
                )

        # Grab any new rivals added during this play session
        rivalnode = request.child('pdata/rival')
        if rivalnode:
            for child in rivalnode.children:
                if child.name != 'r':
                    continue

                extid = child.child_value('id')
                other_userid = self.data.remote.user.from_extid(
                    self.game, self.version, extid)
                if other_userid is None:
                    continue

                self.data.local.user.put_link(
                    self.game,
                    self.version,
                    userid,
                    'rival',
                    other_userid,
                    {},
                )

        # Save player dojo
        dojo = request.child('pdata/dojo')
        if dojo:
            dojoid = dojo.child_value('class')
            clear_type = dojo.child_value('clear_type')
            ar = dojo.child_value('t_ar')
            score = dojo.child_value('t_score')

            # Figure out timestamp stuff
            data = self.data.local.user.get_achievement(
                self.game,
                self.version,
                userid,
                dojoid,
                'dojo',
            ) or ValidatedDict()

            if ar >= data.get_int('ar'):
                # We set a new achievement rate, keep the new values
                record_time = Time.now()
            else:
                # We didn't, keep the old values for achievement rate, but
                # override score and clear_type only if they were better.
                record_time = data.get_int('record_timestamp')
                ar = data.get_int('ar')
                score = max(score, data.get_int('score'))
                clear_type = max(clear_type, data.get_int('clear_type'))

            play_time = Time.now()
            plays = data.get_int('plays') + 1

            self.data.local.user.put_achievement(
                self.game,
                self.version,
                userid,
                dojoid,
                'dojo',
                {
                    'clear_type': clear_type,
                    'ar': ar,
                    'score': score,
                    'plays': plays,
                    'play_timestamp': play_time,
                    'record_timestamp': record_time,
                },
            )

        # Save yurukome stuff
        yurukome_list = request.child('pdata/yurukome_list')
        if yurukome_list:
            for child in yurukome_list.children:
                if child.name != 'yurukome':
                    continue

                yurukome_id = child.child_value('yurukome_id')
                self.data.local.user.put_achievement(
                    self.game,
                    self.version,
                    userid,
                    yurukome_id,
                    'yurukome',
                    {},
                )

        # Save mycourse stuff
        mycoursedict = newprofile.get_dict('mycourse')
        mycourse = request.child('pdata/mycourse')
        if mycourse:
            # Only replace course if it was a new record score-wise.
            score_1 = mycourse.child_value('score_1')
            score_2 = mycourse.child_value('score_2')
            score_3 = mycourse.child_value('score_3')
            score_4 = mycourse.child_value('score_4')
            total = 0
            for score in [score_1, score_2, score_3, score_4]:
                if score is not None and score >= 0:
                    total = total + score

            oldtotal = (mycoursedict.get_int('score_1', 0) +
                        mycoursedict.get_int('score_2', 0) +
                        mycoursedict.get_int('score_3', 0) +
                        mycoursedict.get_int('score_4', 0))

            if total >= oldtotal:
                mycoursedict.replace_int('music_id_1',
                                         mycourse.child_value('music_id_1'))
                mycoursedict.replace_int('note_grade_1',
                                         mycourse.child_value('note_grade_1'))
                mycoursedict.replace_int('score_1', score_1)
                mycoursedict.replace_int('music_id_2',
                                         mycourse.child_value('music_id_2'))
                mycoursedict.replace_int('note_grade_2',
                                         mycourse.child_value('note_grade_2'))
                mycoursedict.replace_int('score_2', score_2)
                mycoursedict.replace_int('music_id_3',
                                         mycourse.child_value('music_id_3'))
                mycoursedict.replace_int('note_grade_3',
                                         mycourse.child_value('note_grade_3'))
                mycoursedict.replace_int('score_3', score_3)
                mycoursedict.replace_int('music_id_4',
                                         mycourse.child_value('music_id_4'))
                mycoursedict.replace_int('note_grade_4',
                                         mycourse.child_value('note_grade_4'))
                mycoursedict.replace_int('score_4', score_4)
                mycoursedict.replace_int('insert_time', Time.now())
        newprofile.replace_dict('mycourse', mycoursedict)

        # Keep track of play statistics
        self.update_play_statistics(userid)

        return newprofile
Esempio n. 25
0
    def __handle_rivalload(self, userid: Optional[UserID], requestdata: Node, response: Node) -> None:
        data = Node.void('data')
        response.add_child(data)
        data.add_child(Node.s32('recordtype', requestdata.child_value('loadflag')))

        thismachine = self.data.local.machine.get_machine(self.config['machine']['pcbid'])
        machines_by_id: Dict[int, Optional[Machine]] = {thismachine.id: thismachine}

        loadkind = requestdata.child_value('loadflag')
        profiles_by_userid: Dict[UserID, ValidatedDict] = {}

        def get_machine(lid: int) -> Optional[Machine]:
            if lid not in machines_by_id:
                pcbid = self.data.local.machine.from_machine_id(lid)
                if pcbid is None:
                    machines_by_id[lid] = None
                    return None

                machine = self.data.local.machine.get_machine(pcbid)
                if machine is None:
                    machines_by_id[lid] = None
                    return None

                machines_by_id[lid] = machine
            return machines_by_id[lid]

        if loadkind == self.GAME_RIVAL_TYPE_WORLD:
            # Just load all scores for this network
            scores = self.data.remote.music.get_all_records(self.game, self.music_version)
        elif loadkind == self.GAME_RIVAL_TYPE_AREA:
            if thismachine.arcade is not None:
                match_arcade = thismachine.arcade
                match_machine = None
            else:
                match_arcade = None
                match_machine = thismachine.id

            # Load up all scores by any user registered on a machine in the same arcade
            profiles = self.data.local.user.get_all_profiles(self.game, self.version)
            userids: List[UserID] = []
            for userid, profiledata in profiles:
                profiles_by_userid[userid] = profiledata

                # If we have an arcade to match, see if this user's location matches the arcade.
                # If we don't, just match lid directly
                if match_arcade is not None:
                    theirmachine = get_machine(profiledata.get_int('lid'))
                    if theirmachine is not None and theirmachine.arcade == match_arcade:
                        userids.append(userid)
                elif match_machine is not None:
                    if profiledata.get_int('lid') == match_machine:
                        userids.append(userid)

            # Load all scores for users in the area
            scores = self.data.local.music.get_all_records(self.game, self.music_version, userlist=userids)
        elif loadkind == self.GAME_RIVAL_TYPE_MACHINE:
            # Load up all scores and filter them by those earned at this location
            scores = self.data.local.music.get_all_records(self.game, self.music_version, locationlist=[thismachine.id])
        elif loadkind in [
            self.GAME_RIVAL_TYPE_RIVAL1,
            self.GAME_RIVAL_TYPE_RIVAL2,
            self.GAME_RIVAL_TYPE_RIVAL3,
        ]:
            # Load up this user's highscores, format the way the below code expects it
            extid = requestdata.child_value('ddrcode')
            otherid = self.data.remote.user.from_extid(self.game, self.version, extid)
            userscores = self.data.remote.music.get_scores(self.game, self.music_version, otherid)
            scores = [(otherid, score) for score in userscores]
        else:
            # Nothing here
            scores = []

        missing_users = [userid for (userid, _) in scores if userid not in profiles_by_userid]
        for (userid, profile) in self.get_any_profiles(missing_users):
            profiles_by_userid[userid] = profile

        for userid, score in scores:
            if profiles_by_userid.get(userid) is None:
                raise Exception('Logic error, couldn\'t find any profile for {}'.format(userid))
            profiledata = profiles_by_userid[userid]

            record = Node.void('record')
            data.add_child(record)
            record.add_child(Node.u32('mcode', score.id))
            record.add_child(Node.u8('notetype', self.db_to_game_chart(score.chart)))
            record.add_child(Node.u8('rank', self.db_to_game_rank(score.data.get_int('rank'))))
            record.add_child(Node.u8('clearkind', self.db_to_game_halo(score.data.get_int('halo'))))
            record.add_child(Node.u8('flagdata', 0))
            record.add_child(Node.string('name', profiledata.get_str('name')))
            record.add_child(Node.s32('area', profiledata.get_int('area', 58)))
            record.add_child(Node.s32('code', profiledata.get_int('extid')))
            record.add_child(Node.s32('score', score.points))
            record.add_child(Node.s32('ghostid', score.key))
Esempio n. 26
0
    def handle_game_3_save_m_request(self, request: Node) -> Node:
        refid = request.child_value('refid')

        if refid is not None:
            userid = self.data.remote.user.from_refid(self.game, self.version, refid)
        else:
            userid = None

        # Doesn't matter if userid is None here, that's an anonymous score
        musicid = request.child_value('music_id')
        chart = request.child_value('music_type')
        points = request.child_value('score')
        combo = request.child_value('max_chain')
        clear_type = self.__game_to_db_clear_type(request.child_value('clear_type'))
        grade = self.__game_to_db_grade(request.child_value('score_grade'))
        stats = {
            'btn_rate': request.child_value('btn_rate'),
            'long_rate': request.child_value('long_rate'),
            'vol_rate': request.child_value('vol_rate'),
            'critical': request.child_value('critical'),
            'near': request.child_value('near'),
            'error': request.child_value('error'),
        }

        # Save the score
        self.update_score(
            userid,
            musicid,
            chart,
            points,
            clear_type,
            grade,
            combo,
            stats,
        )

        # Return a blank response
        return Node.void('game_3')
Esempio n. 27
0
    def handle_player22_request(self, request: Node) -> Optional[Node]:
        method = request.attribute('method')

        if method == 'read':
            refid = request.child_value('ref_id')
            # Pop'n Music 22 doesn't send a modelstring to load old profiles,
            # it just expects us to know. So always look for old profiles in
            # Pop'n 22 land.
            root = self.get_profile_by_refid(refid,
                                             self.OLD_PROFILE_FALLTHROUGH)
            if root is None:
                root = Node.void('player22')
                root.set_attribute('status', str(Status.NO_PROFILE))
            return root

        elif method == 'new':
            refid = request.child_value('ref_id')
            name = request.child_value('name')
            root = self.new_profile_by_refid(refid, name)
            if root is None:
                root = Node.void('player22')
                root.set_attribute('status', str(Status.NO_PROFILE))
            return root

        elif method == 'start':
            return Node.void('player22')

        elif method == 'logout':
            return Node.void('player22')

        elif method == 'write':
            refid = request.child_value('ref_id')

            root = Node.void('player22')
            if refid is None:
                return root

            userid = self.data.remote.user.from_refid(self.game, self.version,
                                                      refid)
            if userid is None:
                return root

            oldprofile = self.get_profile(userid) or ValidatedDict()
            newprofile = self.unformat_profile(userid, request, oldprofile)

            if newprofile is not None:
                self.put_profile(userid, newprofile)

            return root

        elif method == 'conversion':
            refid = request.child_value('ref_id')
            name = request.child_value('name')
            chara = request.child_value('chara')
            root = self.new_profile_by_refid(refid, name, chara)
            if root is None:
                root = Node.void('playerdata')
                root.set_attribute('status', str(Status.NO_PROFILE))
            return root

        elif method == 'write_music':
            refid = request.child_value('ref_id')

            root = Node.void('player22')
            if refid is None:
                return root

            userid = self.data.remote.user.from_refid(self.game, self.version,
                                                      refid)
            if userid is None:
                return root

            songid = request.child_value('music_num')
            chart = {
                self.GAME_CHART_TYPE_EASY: self.CHART_TYPE_EASY,
                self.GAME_CHART_TYPE_NORMAL: self.CHART_TYPE_NORMAL,
                self.GAME_CHART_TYPE_HYPER: self.CHART_TYPE_HYPER,
                self.GAME_CHART_TYPE_EX: self.CHART_TYPE_EX,
            }[request.child_value('sheet_num')]
            medal = request.child_value('clearmedal')
            points = request.child_value('score')
            combo = request.child_value('combo')
            stats = {
                'cool': request.child_value('cool'),
                'great': request.child_value('great'),
                'good': request.child_value('good'),
                'bad': request.child_value('bad')
            }
            medal = {
                self.GAME_PLAY_MEDAL_CIRCLE_FAILED:
                self.PLAY_MEDAL_CIRCLE_FAILED,
                self.GAME_PLAY_MEDAL_DIAMOND_FAILED:
                self.PLAY_MEDAL_DIAMOND_FAILED,
                self.GAME_PLAY_MEDAL_STAR_FAILED: self.PLAY_MEDAL_STAR_FAILED,
                self.GAME_PLAY_MEDAL_EASY_CLEAR: self.PLAY_MEDAL_EASY_CLEAR,
                self.GAME_PLAY_MEDAL_CIRCLE_CLEARED:
                self.PLAY_MEDAL_CIRCLE_CLEARED,
                self.GAME_PLAY_MEDAL_DIAMOND_CLEARED:
                self.PLAY_MEDAL_DIAMOND_CLEARED,
                self.GAME_PLAY_MEDAL_STAR_CLEARED:
                self.PLAY_MEDAL_STAR_CLEARED,
                self.GAME_PLAY_MEDAL_CIRCLE_FULL_COMBO:
                self.PLAY_MEDAL_CIRCLE_FULL_COMBO,
                self.GAME_PLAY_MEDAL_DIAMOND_FULL_COMBO:
                self.PLAY_MEDAL_DIAMOND_FULL_COMBO,
                self.GAME_PLAY_MEDAL_STAR_FULL_COMBO:
                self.PLAY_MEDAL_STAR_FULL_COMBO,
                self.GAME_PLAY_MEDAL_PERFECT: self.PLAY_MEDAL_PERFECT,
            }[medal]
            self.update_score(userid,
                              songid,
                              chart,
                              points,
                              medal,
                              combo=combo,
                              stats=stats)
            return root

        # Invalid method
        return None