Exemple #1
0
    def verify_lobby_entry(self, location: str, extid: int) -> int:
        call = self.call_node()

        lobby = Node.void('lobby')
        lobby.set_attribute('method', 'entry')
        e = Node.void('e')
        lobby.add_child(e)
        e.add_child(Node.s32('eid', 0))
        e.add_child(Node.u16('mid', 79))
        e.add_child(Node.u8('ng', 0))
        e.add_child(Node.s32('uid', extid))
        e.add_child(Node.string('pn', self.NAME))
        e.add_child(Node.s32('exp', 0))
        e.add_child(Node.u8('mg', 0))
        e.add_child(Node.s32('tid', 0))
        e.add_child(Node.string('tn', ''))
        e.add_child(Node.string('lid', location))
        e.add_child(Node.string('sn', ''))
        e.add_child(Node.u8('pref', 51))
        e.add_child(Node.u8_array('ga', [127, 0, 0, 1]))
        e.add_child(Node.u16('gp', 10007))
        e.add_child(Node.u8_array('la', [16, 0, 0, 0]))
        call.add_child(lobby)

        # Swap with server
        resp = self.exchange('', call)

        # Verify that response is correct
        self.assert_path(resp, "response/lobby/eid")
        self.assert_path(resp, "response/lobby/e/eid")
        self.assert_path(resp, "response/lobby/e/mid")
        self.assert_path(resp, "response/lobby/e/ng")
        self.assert_path(resp, "response/lobby/e/uid")
        self.assert_path(resp, "response/lobby/e/pn")
        self.assert_path(resp, "response/lobby/e/exp")
        self.assert_path(resp, "response/lobby/e/mg")
        self.assert_path(resp, "response/lobby/e/tid")
        self.assert_path(resp, "response/lobby/e/tn")
        self.assert_path(resp, "response/lobby/e/lid")
        self.assert_path(resp, "response/lobby/e/sn")
        self.assert_path(resp, "response/lobby/e/pref")
        self.assert_path(resp, "response/lobby/e/ga")
        self.assert_path(resp, "response/lobby/e/gp")
        self.assert_path(resp, "response/lobby/e/la")
        return resp.child_value('lobby/eid')
Exemple #2
0
    def verify_game_save(self, location: str, refid: str, packet: int, block: int, blaster_energy: int) -> None:
        call = self.call_node()

        game = Node.void('game_3')
        call.add_child(game)
        game.set_attribute('method', 'save')
        game.set_attribute('ver', '0')
        game.add_child(Node.string('refid', refid))
        game.add_child(Node.string('locid', location))
        game.add_child(Node.u8('headphone', 0))
        game.add_child(Node.u16('appeal_id', 1001))
        game.add_child(Node.u16('comment_id', 0))
        game.add_child(Node.s32('music_id', 29))
        game.add_child(Node.u8('music_type', 1))
        game.add_child(Node.u8('sort_type', 1))
        game.add_child(Node.u8('narrow_down', 0))
        game.add_child(Node.u8('gauge_option', 0))
        game.add_child(Node.u32('earned_gamecoin_packet', packet))
        game.add_child(Node.u32('earned_gamecoin_block', block))
        item = Node.void('item')
        game.add_child(item)
        info = Node.void('info')
        item.add_child(info)
        info.add_child(Node.u32('id', 1))
        info.add_child(Node.u32('type', 5))
        info.add_child(Node.u32('param', 333333376))
        info = Node.void('info')
        item.add_child(info)
        info.add_child(Node.u32('id', 0))
        info.add_child(Node.u32('type', 5))
        info.add_child(Node.u32('param', 600))
        game.add_child(Node.s32_array('hidden_param', [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]))
        game.add_child(Node.s16('skill_name_id', -1))
        game.add_child(Node.s32('earned_blaster_energy', blaster_energy))
        game.add_child(Node.u32('blaster_count', 0))
        printn = Node.void('print')
        game.add_child(printn)
        printn.add_child(Node.s32('count', 0))
        ea_shop = Node.void('ea_shop')
        game.add_child(ea_shop)
        ea_shop.add_child(Node.s32('used_packet_booster', 0))
        ea_shop.add_child(Node.s32('used_block_booster', 0))
        game.add_child(Node.s8('start_option', 0))

        # Swap with server
        resp = self.exchange('', call)

        # Verify that response is correct
        self.assert_path(resp, "response/game_3")
Exemple #3
0
    def verify_game_load(self, cardid: str, refid: str, msg_type: str) -> Dict[str, Any]:
        call = self.call_node()

        game = Node.void('game_3')
        call.add_child(game)
        game.set_attribute('method', 'load')
        game.set_attribute('ver', '0')
        game.add_child(Node.string('dataid', refid))
        game.add_child(Node.string('cardid', cardid))
        game.add_child(Node.string('refid', refid))

        # Swap with server
        resp = self.exchange('', call)

        # Verify that response is correct
        if msg_type == "new":
            self.assert_path(resp, "response/game_3/result")
            if resp.child_value('game_3/result') != 1:
                raise Exception("Invalid result for new profile!")
            return None

        if msg_type == "existing":
            self.assert_path(resp, "response/game_3/name")
            self.assert_path(resp, "response/game_3/code")
            self.assert_path(resp, "response/game_3/gamecoin_packet")
            self.assert_path(resp, "response/game_3/gamecoin_block")
            self.assert_path(resp, "response/game_3/skill_name_id")
            self.assert_path(resp, "response/game_3/hidden_param")
            self.assert_path(resp, "response/game_3/blaster_energy")
            self.assert_path(resp, "response/game_3/blaster_count")
            self.assert_path(resp, "response/game_3/play_count")
            self.assert_path(resp, "response/game_3/daily_count")
            self.assert_path(resp, "response/game_3/play_chain")
            self.assert_path(resp, "response/game_3/item")
            self.assert_path(resp, "response/game_3/skill/course_all")
            self.assert_path(resp, "response/game_3/story")

            items: Dict[int, Dict[int, int]] = {}
            for child in resp.child('game_3/item').children:
                if child.name != 'info':
                    continue

                itype = child.child_value('type')
                iid = child.child_value('id')
                param = child.child_value('param')

                if itype not in items:
                    items[itype] = {}
                items[itype][iid] = param

            courses: Dict[int, Dict[int, Dict[str, int]]] = {}
            for child in resp.child('game_3/skill/course_all').children:
                if child.name != 'd':
                    continue

                crsid = child.child_value('crsid')
                season = child.child_value('ssnid')
                achievement_rate = child.child_value('ar')
                clear_type = child.child_value('ct')

                if season not in courses:
                    courses[season] = {}
                courses[season][crsid] = {
                    'achievement_rate': achievement_rate,
                    'clear_type': clear_type,
                }

            return {
                'name': resp.child_value('game_3/name'),
                'packet': resp.child_value('game_3/gamecoin_packet'),
                'block': resp.child_value('game_3/gamecoin_block'),
                'blaster_energy': resp.child_value('game_3/blaster_energy'),
                'items': items,
                'courses': courses,
            }
        else:
            raise Exception(f"Invalid game load type {msg_type}")
Exemple #4
0
 def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node:
     """
     Base handler for a profile. Given a userid and a profile dictionary,
     return a Node representing a profile. Should be overridden.
     """
     return Node.void('game')
Exemple #5
0
    def verify_game_load(self, ref_id: str, msg_type: str) -> Dict[str, Any]:
        call = self.call_node()
        game = Node.void('game')
        call.add_child(game)
        game.set_attribute('method', 'load')
        game.set_attribute('ver', '2014032400')
        game.set_attribute('refid', ref_id)

        # Swap with server
        resp = self.exchange('', call)

        if msg_type == 'new':
            # Verify that response is correct
            self.assert_path(resp, "response/game/@none")
            return {}
        if msg_type == 'existing':
            # Verify existing profile and return info
            self.assert_path(resp, "response/game/seq")
            self.assert_path(resp, "response/game/code")
            self.assert_path(resp, "response/game/name")
            self.assert_path(resp, "response/game/area")
            self.assert_path(resp, "response/game/cnt_s")
            self.assert_path(resp, "response/game/cnt_d")
            self.assert_path(resp, "response/game/cnt_b")
            self.assert_path(resp, "response/game/cnt_m0")
            self.assert_path(resp, "response/game/cnt_m1")
            self.assert_path(resp, "response/game/cnt_m2")
            self.assert_path(resp, "response/game/cnt_m3")
            self.assert_path(resp, "response/game/cnt_m4")
            self.assert_path(resp, "response/game/cnt_m5")
            self.assert_path(resp, "response/game/exp")
            self.assert_path(resp, "response/game/exp_o")
            self.assert_path(resp, "response/game/star")
            self.assert_path(resp, "response/game/star_c")
            self.assert_path(resp, "response/game/combo")
            self.assert_path(resp, "response/game/timing_diff")
            self.assert_path(resp, "response/game/chara")
            self.assert_path(resp, "response/game/chara_opt")
            self.assert_path(resp, "response/game/daycount/@playcount")
            self.assert_path(resp, "response/game/dailycombo/@daily_combo")
            self.assert_path(resp, "response/game/dailycombo/@daily_combo_lv")
            self.assert_path(resp, "response/game/last/@cate")
            self.assert_path(resp, "response/game/last/@cid")
            self.assert_path(resp, "response/game/last/@ctype")
            self.assert_path(resp, "response/game/last/@fri")
            self.assert_path(resp, "response/game/last/@mid")
            self.assert_path(resp, "response/game/last/@mode")
            self.assert_path(resp, "response/game/last/@mtype")
            self.assert_path(resp, "response/game/last/@rival1")
            self.assert_path(resp, "response/game/last/@rival2")
            self.assert_path(resp, "response/game/last/@rival3")
            self.assert_path(resp, "response/game/last/@sid")
            self.assert_path(resp, "response/game/last/@sort")
            self.assert_path(resp, "response/game/last/@style")
            self.assert_path(resp, "response/game/result_star/@slot1")
            self.assert_path(resp, "response/game/result_star/@slot2")
            self.assert_path(resp, "response/game/result_star/@slot3")
            self.assert_path(resp, "response/game/result_star/@slot4")
            self.assert_path(resp, "response/game/result_star/@slot5")
            self.assert_path(resp, "response/game/result_star/@slot6")
            self.assert_path(resp, "response/game/result_star/@slot7")
            self.assert_path(resp, "response/game/result_star/@slot8")
            self.assert_path(resp, "response/game/result_star/@slot9")
            self.assert_path(resp, "response/game/target/@flag")
            self.assert_path(resp, "response/game/target/@setnum")
            self.assert_path(resp, "response/game/gr_s/@gr1")
            self.assert_path(resp, "response/game/gr_s/@gr2")
            self.assert_path(resp, "response/game/gr_s/@gr3")
            self.assert_path(resp, "response/game/gr_s/@gr4")
            self.assert_path(resp, "response/game/gr_s/@gr5")
            self.assert_path(resp, "response/game/gr_d/@gr1")
            self.assert_path(resp, "response/game/gr_d/@gr2")
            self.assert_path(resp, "response/game/gr_d/@gr3")
            self.assert_path(resp, "response/game/gr_d/@gr4")
            self.assert_path(resp, "response/game/gr_d/@gr5")
            self.assert_path(resp, "response/game/opt")
            self.assert_path(resp, "response/game/opt_ex")
            self.assert_path(resp, "response/game/flag")
            self.assert_path(resp, "response/game/rank")
            for i in range(55):
                self.assert_path(resp, f"response/game/play_area/@play_cnt{i}")

            gr_s = resp.child('game/gr_s')
            gr_d = resp.child('game/gr_d')

            return {
                'name':
                resp.child_value('game/name'),
                'ext_id':
                resp.child_value('game/code'),
                'single_plays':
                resp.child_value('game/cnt_s'),
                'double_plays':
                resp.child_value('game/cnt_d'),
                'groove_single': [
                    int(gr_s.attribute('gr1')),
                    int(gr_s.attribute('gr2')),
                    int(gr_s.attribute('gr3')),
                    int(gr_s.attribute('gr4')),
                    int(gr_s.attribute('gr5')),
                ],
                'groove_double': [
                    int(gr_d.attribute('gr1')),
                    int(gr_d.attribute('gr2')),
                    int(gr_d.attribute('gr3')),
                    int(gr_d.attribute('gr4')),
                    int(gr_d.attribute('gr5')),
                ],
            }

        raise Exception('Unknown load type!')
Exemple #6
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
Exemple #7
0
 def handle_log_opsetting_request(self, request: Node) -> Node:
     return Node.void('log')
Exemple #8
0
    def verify_pcb23_boot(self, loc: str) -> None:
        call = self.call_node()

        # Construct node
        pcb23 = Node.void('pcb23')
        call.add_child(pcb23)
        pcb23.set_attribute('method', 'boot')
        pcb23.add_child(Node.string('loc_id', loc))
        pcb23.add_child(Node.u8('loc_type', 0))
        pcb23.add_child(Node.string('loc_name', ''))
        pcb23.add_child(Node.string('country', 'US'))
        pcb23.add_child(Node.string('region', '.'))
        pcb23.add_child(Node.s16('pref', 51))
        pcb23.add_child(Node.string('customer', ''))
        pcb23.add_child(Node.string('company', ''))
        pcb23.add_child(Node.ipv4('gip', '127.0.0.1'))
        pcb23.add_child(Node.u16('gp', 10011))
        pcb23.add_child(Node.string('rom_number', 'M39-JB-G01'))
        pcb23.add_child(Node.u64('c_drive', 10028228608))
        pcb23.add_child(Node.u64('d_drive', 47945170944))
        pcb23.add_child(Node.u64('e_drive', 10394677248))
        pcb23.add_child(Node.string('etc', ''))

        # Swap with server
        resp = self.exchange('', call)

        # Verify that response is correct
        self.assert_path(resp, "response/pcb23/@status")
Exemple #9
0
    def verify_player23_read(
            self, ref_id: str,
            msg_type: str) -> Dict[str, Dict[int, Dict[str, int]]]:
        call = self.call_node()

        # Construct node
        player23 = Node.void('player23')
        call.add_child(player23)
        player23.set_attribute('method', 'read')

        player23.add_child(Node.string('ref_id', ref_id))
        player23.add_child(Node.s8('pref', 51))

        # Swap with server
        resp = self.exchange('', call)

        if msg_type == 'new':
            # Verify that response is correct
            self.assert_path(resp, "response/player23/result")
            status = resp.child_value('player23/result')
            if status != 2:
                raise Exception(
                    f'Reference ID \'{ref_id}\' returned invalid status \'{status}\''
                )

            return {
                'medals': {},
                'items': {},
                'characters': {},
                'lumina': {},
            }
        elif msg_type == 'query':
            # Verify that the response is correct
            self.__verify_profile(resp)

            self.assert_path(resp, "response/player23/result")
            status = resp.child_value('player23/result')
            if status != 0:
                raise Exception(
                    f'Reference ID \'{ref_id}\' returned invalid status \'{status}\''
                )
            name = resp.child_value('player23/account/name')
            if name != self.NAME:
                raise Exception(
                    f'Invalid name \'{name}\' returned for Ref ID \'{ref_id}\''
                )

            # Medals and items
            items: Dict[int, Dict[str, int]] = {}
            medals: Dict[int, Dict[str, int]] = {}
            charas: Dict[int, Dict[str, int]] = {}
            for obj in resp.child('player23').children:
                if obj.name == 'medal':
                    medals[obj.child_value('medal_id')] = {
                        'level': obj.child_value('level'),
                        'exp': obj.child_value('exp'),
                    }
                elif obj.name == 'item':
                    items[obj.child_value('id')] = {
                        'type': obj.child_value('type'),
                        'param': obj.child_value('param'),
                    }
                elif obj.name == 'chara_param':
                    charas[obj.child_value('chara_id')] = {
                        'friendship': obj.child_value('friendship'),
                    }

            return {
                'medals': medals,
                'items': items,
                'characters': charas,
                'lumina': {
                    0: {
                        'lumina': resp.child_value('player23/account/lumina')
                    }
                },
            }
        else:
            raise Exception(f'Unrecognized message type \'{msg_type}\'')
Exemple #10
0
 def handle_lobby_request(self, request: Node) -> Optional[Node]:
     # Stub out the entire lobby service
     return Node.void('lobby')
Exemple #11
0
    def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node:
        root = Node.void('playerdata')

        # Set up the base profile
        base = Node.void('base')
        root.add_child(base)
        base.add_child(Node.string('name', profile.get_str('name', 'なし')))
        base.add_child(Node.string('g_pm_id', ID.format_extid(profile.get_int('extid'))))
        base.add_child(Node.u8('mode', profile.get_int('mode', 0)))
        base.add_child(Node.s8('button', profile.get_int('button', 0)))
        base.add_child(Node.s8('last_play_flag', profile.get_int('last_play_flag', -1)))
        base.add_child(Node.u8('medal_and_friend', profile.get_int('medal_and_friend', 0)))
        base.add_child(Node.s8('category', profile.get_int('category', -1)))
        base.add_child(Node.s8('sub_category', profile.get_int('sub_category', -1)))
        base.add_child(Node.s16('chara', profile.get_int('chara', -1)))
        base.add_child(Node.s8('chara_category', profile.get_int('chara_category', -1)))
        base.add_child(Node.u8('collabo', profile.get_int('collabo', 255)))
        base.add_child(Node.u8('sheet', profile.get_int('sheet', 0)))
        base.add_child(Node.s8('tutorial', profile.get_int('tutorial', 0)))
        base.add_child(Node.s32('music_open_pt', profile.get_int('music_open_pt', 0)))
        base.add_child(Node.s8('is_conv', -1))
        base.add_child(Node.s32('option', profile.get_int('option', 0)))
        base.add_child(Node.s16('music', profile.get_int('music', -1)))
        base.add_child(Node.u16('ep', profile.get_int('ep', 0)))
        base.add_child(Node.s32_array('sp_color_flg', profile.get_int_array('sp_color_flg', 2)))
        base.add_child(Node.s32('read_news', profile.get_int('read_news', 0)))
        base.add_child(Node.s16('consecutive_days_coupon', profile.get_int('consecutive_days_coupon', 0)))
        base.add_child(Node.s8('staff', 0))

        # Player card section
        player_card_dict = profile.get_dict('player_card')
        player_card = Node.void('player_card')
        root.add_child(player_card)
        player_card.add_child(Node.u8_array('title', player_card_dict.get_int_array('title', 2, [0, 1])))
        player_card.add_child(Node.u8('frame', player_card_dict.get_int('frame')))
        player_card.add_child(Node.u8('base', player_card_dict.get_int('base')))
        player_card.add_child(Node.u8_array('seal', player_card_dict.get_int_array('seal', 2)))
        player_card.add_child(Node.s32_array('get_title', player_card_dict.get_int_array('get_title', 4)))
        player_card.add_child(Node.s32('get_frame', player_card_dict.get_int('get_frame')))
        player_card.add_child(Node.s32('get_base', player_card_dict.get_int('get_base')))
        player_card.add_child(Node.s32_array('get_seal', player_card_dict.get_int_array('get_seal', 2)))

        # Player card EX section
        player_card_ex = Node.void('player_card_ex')
        root.add_child(player_card_ex)
        player_card_ex.add_child(Node.s32('get_title_ex', player_card_dict.get_int('get_title_ex')))
        player_card_ex.add_child(Node.s32('get_frame_ex', player_card_dict.get_int('get_frame_ex')))
        player_card_ex.add_child(Node.s32('get_base_ex', player_card_dict.get_int('get_base_ex')))
        player_card_ex.add_child(Node.s32('get_seal_ex', player_card_dict.get_int('get_seal_ex')))

        # Statistics section and scores section
        statistics = self.get_play_statistics(userid)
        last_play_date = statistics.get_int_array('last_play_date', 3)
        today_play_date = Time.todays_date()
        if (
            last_play_date[0] == today_play_date[0] and
            last_play_date[1] == today_play_date[1] and
            last_play_date[2] == today_play_date[2]
        ):
            today_count = statistics.get_int('today_plays', 0)
        else:
            today_count = 0
        base.add_child(Node.s32('total_play_cnt', statistics.get_int('total_plays', 0)))
        base.add_child(Node.s16('today_play_cnt', today_count))
        base.add_child(Node.s16('consecutive_days', statistics.get_int('consecutive_days', 0)))

        # Number of rivals that are active for this version.
        links = self.data.local.user.get_links(self.game, self.version, userid)
        rivalcount = 0
        for link in links:
            if link.type != 'rival':
                continue

            if not self.has_profile(link.other_userid):
                continue

            # This profile is valid.
            rivalcount += 1
        base.add_child(Node.u8('active_fr_num', rivalcount))

        last_played = [x[0] for x in self.data.local.music.get_last_played(self.game, self.music_version, userid, 3)]
        most_played = [x[0] for x in self.data.local.music.get_most_played(self.game, self.music_version, userid, 20)]
        while len(last_played) < 3:
            last_played.append(-1)
        while len(most_played) < 20:
            most_played.append(-1)

        hiscore_array = [0] * int((((self.GAME_MAX_MUSIC_ID * 4) * 17) + 7) / 8)
        clear_medal = [0] * self.GAME_MAX_MUSIC_ID
        clear_medal_sub = [0] * self.GAME_MAX_MUSIC_ID

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

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

            points = score.points
            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)

        player_card.add_child(Node.s16_array('best_music', most_played[0:3]))
        base.add_child(Node.s16_array('my_best', most_played))
        base.add_child(Node.s16_array('latest_music', last_played))
        base.add_child(Node.u16_array('clear_medal', clear_medal))
        base.add_child(Node.u8_array('clear_medal_sub', clear_medal_sub))

        # Goes outside of base for some reason
        root.add_child(Node.binary('hiscore', hiscore))

        # Net VS section
        netvs = Node.void('netvs')
        root.add_child(netvs)
        netvs.add_child(Node.s32_array('get_ojama', [0, 0]))
        netvs.add_child(Node.s32('rank_point', 0))
        netvs.add_child(Node.s32('play_point', 0))
        netvs.add_child(Node.s16_array('record', [0, 0, 0, 0, 0, 0]))
        netvs.add_child(Node.u8('rank', 0))
        netvs.add_child(Node.s8_array('ojama_condition', [0] * 74))
        netvs.add_child(Node.s8_array('set_ojama', [0, 0, 0]))
        netvs.add_child(Node.s8_array('set_recommend', [0, 0, 0]))
        netvs.add_child(Node.s8_array('jewelry', [0] * 15))
        for dialog in [0, 1, 2, 3, 4, 5]:
            # TODO: Configure this, maybe?
            netvs.add_child(Node.string('dialog', f'dialog#{dialog}'))

        sp_data = Node.void('sp_data')
        root.add_child(sp_data)
        sp_data.add_child(Node.s32('sp', profile.get_int('sp', 0)))

        reflec_data = Node.void('reflec_data')
        root.add_child(reflec_data)
        reflec_data.add_child(Node.s8_array('reflec', profile.get_int_array('reflec', 2)))

        # Navigate section
        navigate_dict = profile.get_dict('navigate')
        navigate = Node.void('navigate')
        root.add_child(navigate)
        navigate.add_child(Node.s8('genre', navigate_dict.get_int('genre')))
        navigate.add_child(Node.s8('image', navigate_dict.get_int('image')))
        navigate.add_child(Node.s8('level', navigate_dict.get_int('level')))
        navigate.add_child(Node.s8('ojama', navigate_dict.get_int('ojama')))
        navigate.add_child(Node.s16('limit_num', navigate_dict.get_int('limit_num')))
        navigate.add_child(Node.s8('button', navigate_dict.get_int('button')))
        navigate.add_child(Node.s8('life', navigate_dict.get_int('life')))
        navigate.add_child(Node.s16('progress', navigate_dict.get_int('progress')))

        return root
Exemple #12
0
    def handle_game_request(self, request: Node) -> Optional[Node]:
        method = request.attribute('method')

        if method == 'get':
            # TODO: Hook these up to config so we can change this
            root = Node.void('game')
            root.add_child(Node.s32('game_phase', 2))
            root.add_child(Node.s32('ir_phase', 0))
            root.add_child(Node.s32('event_phase', 5))
            root.add_child(Node.s32('netvs_phase', 0))
            root.add_child(Node.s32('card_phase', 6))
            root.add_child(Node.s32('illust_phase', 2))
            root.add_child(Node.s32('psp_phase', 5))
            root.add_child(Node.s32('other_phase', 1))
            root.add_child(Node.s32('jubeat_phase', 1))
            root.add_child(Node.s32('public_phase', 3))
            root.add_child(Node.s32('kac_phase', 2))
            root.add_child(Node.s32('local_matching', 1))
            root.add_child(Node.s32('n_matching_sec', 60))
            root.add_child(Node.s32('l_matching_sec', 60))
            root.add_child(Node.s32('is_check_cpu', 0))
            root.add_child(Node.s32('week_no', 0))
            root.add_child(Node.s32_array('ng_illust', [0] * 10))
            root.add_child(Node.s16_array('sel_ranking', [-1] * 10))
            root.add_child(Node.s16_array('up_ranking', [-1] * 10))
            return root

        if method == 'active':
            # Update the name of this cab for admin purposes
            self.update_machine_name(request.child_value('shop_name'))
            return Node.void('game')

        if method == 'taxphase':
            return Node.void('game')

        # Invalid method
        return None
Exemple #13
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
Exemple #14
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
Exemple #15
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')
Exemple #16
0
    def verify_player23_write(
        self,
        ref_id: str,
        medal: Optional[Dict[str, int]] = None,
        item: Optional[Dict[str, int]] = None,
        character: Optional[Dict[str, int]] = None,
    ) -> None:
        call = self.call_node()

        # Construct node
        player23 = Node.void('player23')
        call.add_child(player23)
        player23.set_attribute('method', 'write')
        player23.add_child(Node.string('ref_id', ref_id))

        # Add required children
        config = Node.void('config')
        player23.add_child(config)
        config.add_child(Node.s16('chara', 1543))

        if medal is not None:
            medalnode = Node.void('medal')
            player23.add_child(medalnode)
            medalnode.add_child(Node.s16('medal_id', medal['id']))
            medalnode.add_child(Node.s16('level', medal['level']))
            medalnode.add_child(Node.s32('exp', medal['exp']))
            medalnode.add_child(Node.s32('set_count', 0))
            medalnode.add_child(Node.s32('get_count', 0))

        if item is not None:
            itemnode = Node.void('item')
            player23.add_child(itemnode)
            itemnode.add_child(Node.u8('type', item['type']))
            itemnode.add_child(Node.u16('id', item['id']))
            itemnode.add_child(Node.u16('param', item['param']))
            itemnode.add_child(Node.bool('is_new', False))

        if character is not None:
            chara_param = Node.void('chara_param')
            player23.add_child(chara_param)
            chara_param.add_child(Node.u16('chara_id', character['id']))
            chara_param.add_child(
                Node.u16('friendship', character['friendship']))

        # Swap with server
        resp = self.exchange('', call)
        self.assert_path(resp, "response/player23/@status")
Exemple #17
0
    def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node:
        statistics = self.get_play_statistics(userid)
        game_config = self.get_game_config()
        achievements = self.data.local.user.get_achievements(self.game, self.version, userid)
        scores = self.data.remote.music.get_scores(self.game, self.version, userid)
        root = Node.void('player')
        pdata = Node.void('pdata')
        root.add_child(pdata)

        base = Node.void('base')
        pdata.add_child(base)
        base.add_child(Node.s32('uid', profile.get_int('extid')))
        base.add_child(Node.string('name', profile.get_str('name')))
        base.add_child(Node.s16('lv', profile.get_int('lvl')))
        base.add_child(Node.s32('exp', profile.get_int('exp')))
        base.add_child(Node.s16('mg', profile.get_int('mg')))
        base.add_child(Node.s16('ap', profile.get_int('ap')))
        base.add_child(Node.s32('flag', profile.get_int('flag')))

        last_play_date = statistics.get_int_array('last_play_date', 3)
        today_play_date = Time.todays_date()
        if (
            last_play_date[0] == today_play_date[0] and
            last_play_date[1] == today_play_date[1] and
            last_play_date[2] == today_play_date[2]
        ):
            today_count = statistics.get_int('today_plays', 0)
        else:
            today_count = 0

        con = Node.void('con')
        pdata.add_child(con)
        con.add_child(Node.s32('day', today_count))
        con.add_child(Node.s32('cnt', statistics.get_int('total_plays')))
        con.add_child(Node.s32('last', statistics.get_int('last_play_timestamp')))
        con.add_child(Node.s32('now', Time.now()))

        team = Node.void('team')
        pdata.add_child(team)
        team.add_child(Node.s32('id', -1))
        team.add_child(Node.string('name', ''))

        custom = Node.void('custom')
        customdict = profile.get_dict('custom')
        pdata.add_child(custom)
        custom.add_child(Node.u8('bgm_m', customdict.get_int('bgm_m')))
        custom.add_child(Node.u8('st_f', customdict.get_int('st_f')))
        custom.add_child(Node.u8('st_bg', customdict.get_int('st_bg')))
        custom.add_child(Node.u8('st_bg_b', customdict.get_int('st_bg_b')))
        custom.add_child(Node.u8('eff_e', customdict.get_int('eff_e')))
        custom.add_child(Node.u8('se_s', customdict.get_int('se_s')))
        custom.add_child(Node.u8('se_s_v', customdict.get_int('se_s_v')))

        released = Node.void('released')
        pdata.add_child(released)

        for item in achievements:
            if item.type[:5] != 'item_':
                continue
            itemtype = int(item.type[5:])
            if game_config.get_bool('force_unlock_songs') and itemtype == 0:
                # Don't echo unlocks when we're force unlocking, we'll do it later
                continue

            info = Node.void('info')
            released.add_child(info)
            info.add_child(Node.u8('type', itemtype))
            info.add_child(Node.u16('id', item.id))

        if game_config.get_bool('force_unlock_songs'):
            songs = {song.id for song in self.data.local.music.get_all_songs(self.game, self.version)}

            for songid in songs:
                info = Node.void('info')
                released.add_child(info)
                info.add_child(Node.u8('type', 0))
                info.add_child(Node.u16('id', songid))

        # Scores
        record = Node.void('record')
        pdata.add_child(record)

        for score in scores:
            rec = Node.void('rec')
            record.add_child(rec)
            rec.add_child(Node.u16('mid', score.id))
            rec.add_child(Node.u8('ng', score.chart))
            rec.add_child(Node.s32('win', score.data.get_dict('stats').get_int('win')))
            rec.add_child(Node.s32('lose', score.data.get_dict('stats').get_int('lose')))
            rec.add_child(Node.s32('draw', score.data.get_dict('stats').get_int('draw')))
            rec.add_child(Node.u8('ct', self.__db_to_game_clear_type(score.data.get_int('clear_type'), score.data.get_int('combo_type'))))
            rec.add_child(Node.s16('ar', int(score.data.get_int('achievement_rate') / 10)))
            rec.add_child(Node.s16('bs', score.points))
            rec.add_child(Node.s16('mc', score.data.get_int('combo')))
            rec.add_child(Node.s16('bmc', score.data.get_int('miss_count')))

        # In original ReflecBeat, the entire battle log was returned for each battle.
        # We don't support storing all of that info, so don't return anything here.
        blog = Node.void('blog')
        pdata.add_child(blog)

        # Comment (seems unused?)
        pdata.add_child(Node.string('cmnt', ''))

        return root
Exemple #18
0
    def verify_player23_write_music(self, ref_id: str,
                                    score: Dict[str, Any]) -> None:
        call = self.call_node()

        # Construct node
        player23 = Node.void('player23')
        call.add_child(player23)
        player23.set_attribute('method', 'write_music')
        player23.add_child(Node.string('ref_id', ref_id))
        player23.add_child(Node.string('data_id', ref_id))
        player23.add_child(Node.string('name', self.NAME))
        player23.add_child(Node.u8('stage', 0))
        player23.add_child(Node.s16('music_num', score['id']))
        player23.add_child(Node.u8('sheet_num', score['chart']))
        player23.add_child(Node.u8('clearmedal', score['medal']))
        player23.add_child(Node.s32('score', score['score']))
        player23.add_child(Node.s16('combo', 0))
        player23.add_child(Node.s16('cool', 0))
        player23.add_child(Node.s16('great', 0))
        player23.add_child(Node.s16('good', 0))
        player23.add_child(Node.s16('bad', 0))

        # Swap with server
        resp = self.exchange('', call)
        self.assert_path(resp, "response/player23/@status")
Exemple #19
0
 def handle_log_pcb_status_request(self, request: Node) -> Node:
     return Node.void('log')
Exemple #20
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
Exemple #21
0
 def handle_log_play_request(self, request: Node) -> Node:
     return Node.void('log')
Exemple #22
0
    def handle_lobby_entry_request(self, request: Node) -> Node:
        root = Node.void('lobby')

        # 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'),
                    'lid': request.child_value('e/lid'),
                    'sn': request.child_value('e/sn'),
                    'pref': request.child_value('e/pref'),
                    '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('exp', profile.get_int('exp')))
            e.add_child(Node.u8('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.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.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
Exemple #23
0
    def handle(self, tree: Node) -> Optional[Node]:
        """
        Given a packet from a game, handle it and return a response.

        Parameters:
            tree - A Node representing the root of a tree. Expected to
                   come from an external game.

        Returns:
            A Node representing the root of a response tree, or None if
            we had a problem parsing or generating a response.
        """
        self.log("Received request:\n{}", tree)

        if tree.name != 'call':
            # Invalid request
            self.log("Invalid root node {}", tree.name)
            return None

        if len(tree.children) != 1:
            # Invalid request
            self.log("Invalid number of children for root node")
            return None

        modelstring = tree.attribute('model')
        model = Model.from_modelstring(modelstring)
        pcbid = tree.attribute('srcid')

        # If we are enforcing, bail out if we don't recognize thie ID
        pcb = self.__data.local.machine.get_machine(pcbid)
        if self.__config['server']['enforce_pcbid'] and pcb is None:
            self.log("Unrecognized PCBID {}", pcbid)
            raise UnrecognizedPCBIDException(
                pcbid, modelstring, self.__config['client']['address'])

        # If we don't have a Machine, but we aren't enforcing, we must create it
        if pcb is None:
            pcb = self.__data.local.machine.create_machine(pcbid)

        request = tree.children[0]

        config = copy.copy(self.__config)
        config['machine'] = {
            'pcbid': pcbid,
            'arcade': pcb.arcade,
        }

        # If the machine we looked up is in an arcade, override the global
        # paseli settings with the arcade paseli settings.
        if pcb.arcade is not None:
            arcade = self.__data.local.machine.get_arcade(pcb.arcade)
            if arcade is not None:
                config['paseli']['enabled'] = arcade.data.get_bool(
                    'paseli_enabled')
                config['paseli']['infinite'] = arcade.data.get_bool(
                    'paseli_infinite')
                if arcade.data.get_bool('mask_services_url'):
                    # Mask the address, no matter what the server settings are
                    config['server']['uri'] = None
        # If we don't have a server URI, we should add the default
        if 'uri' not in config['server']:
            config['server']['uri'] = None

        game = Base.create(self.__data, config, model)
        method = request.attribute('method')
        response = None

        # If we are enforcing, make sure the PCBID isn't specified to be
        # game-specific
        if self.__config['server']['enforce_pcbid'] and pcb.game is not None:
            if pcb.game != game.game:
                self.log(
                    "PCBID {} assigned to game {}, but connected from game {}",
                    pcbid, pcb.game, game.game)
                raise UnrecognizedPCBIDException(
                    pcbid, modelstring, self.__config['client']['address'])
            if pcb.version is not None:
                if pcb.version > 0 and pcb.version != game.version:
                    self.log(
                        "PCBID {} assigned to game {} version {}, but connected from game {} version {}",
                        pcbid,
                        pcb.game,
                        pcb.version,
                        game.game,
                        game.version,
                    )
                    raise UnrecognizedPCBIDException(
                        pcbid, modelstring, self.__config['client']['address'])
                if pcb.version < 0 and (-pcb.version) < game.version:
                    self.log(
                        "PCBID {} assigned to game {} maximum version {}, but connected from game {} version {}",
                        pcbid,
                        pcb.game,
                        -pcb.version,
                        game.game,
                        game.version,
                    )
                    raise UnrecognizedPCBIDException(
                        pcbid, modelstring, self.__config['client']['address'])

        # First, try to handle with specific service/method function
        try:
            handler = getattr(
                game, 'handle_{}_{}_request'.format(request.name, method))
        except AttributeError:
            handler = None
        if handler is not None:
            response = handler(request)

        if response is None:
            # Now, try to pass it off to a generic service handler
            try:
                handler = getattr(game,
                                  'handle_{}_request'.format(request.name))
            except AttributeError:
                handler = None
            if handler is not None:
                response = handler(request)

        if response is None:
            # Unrecognized handler
            self.log("Unrecognized service {} method {}".format(
                request.name, method))
            return None

        # Make sure we have a status value if one wasn't provided
        if 'status' not in response.attributes:
            response.set_attribute('status', str(Status.SUCCESS))

        root = Node.void('response')
        root.add_child(response)
        root.set_attribute('dstid', pcbid)

        self.log("Sending response:\n{}", root)

        return root
Exemple #24
0
    def handle_lobby_read_request(self, request: Node) -> Node:
        root = Node.void('lobby')

        # Look up all lobbies matching the criteria specified
        mg = request.child_value('m_grade')  # noqa: F841
        extid = request.child_value('uid')
        limit = request.child_value('max')
        userid = self.data.remote.user.from_extid(self.game, self.version, extid)
        if userid is not None:
            lobbies = self.data.local.lobby.get_all_lobbies(self.game, self.version)
            for (user, lobby) in lobbies:
                if limit <= 0:
                    break

                if user == userid:
                    # If we have our own lobby, don't return it
                    continue

                profile = self.get_profile(user)
                if profile is None:
                    # No profile info, don't return this lobby
                    continue

                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('exp', profile.get_int('exp')))
                e.add_child(Node.u8('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.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.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)))

                limit = limit - 1

        return root
Exemple #25
0
    def verify_eventlog_write(self, location: str) -> None:
        call = self.call_node()

        # Construct node
        eventlog = Node.void('eventlog')
        call.add_child(eventlog)
        eventlog.set_attribute('method', 'write')
        eventlog.add_child(Node.u32('retrycnt', 0))
        data = Node.void('data')
        eventlog.add_child(data)
        data.add_child(Node.string('eventid', 'S_PWRON'))
        data.add_child(Node.s32('eventorder', 0))
        data.add_child(Node.u64('pcbtime', int(time.time() * 1000)))
        data.add_child(Node.s64('gamesession', -1))
        data.add_child(Node.string('strdata1', '2.3.8'))
        data.add_child(Node.string('strdata2', ''))
        data.add_child(Node.s64('numdata1', 1))
        data.add_child(Node.s64('numdata2', 0))
        data.add_child(Node.string('locationid', location))

        # Swap with server
        resp = self.exchange('', call)

        # Verify that response is correct
        self.assert_path(resp, "response/eventlog/gamesession")
        self.assert_path(resp, "response/eventlog/logsendflg")
        self.assert_path(resp, "response/eventlog/logerrlevel")
        self.assert_path(resp, "response/eventlog/evtidnosendflg")
Exemple #26
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')
Exemple #27
0
    def verify_game_buy(self, refid: str, catalogtype: int, catalogid: int, currencytype: int, price: int, itemtype: int, itemid: int, param: int, success: bool) -> None:
        call = self.call_node()

        game = Node.void('game_3')
        call.add_child(game)
        game.set_attribute('ver', '0')
        game.set_attribute('method', 'buy')
        game.add_child(Node.string('refid', refid))
        game.add_child(Node.u8('catalog_type', catalogtype))
        game.add_child(Node.u32('catalog_id', catalogid))
        game.add_child(Node.u32('earned_gamecoin_packet', 0))
        game.add_child(Node.u32('earned_gamecoin_block', 0))
        game.add_child(Node.u32('currency_type', currencytype))
        item = Node.void('item')
        game.add_child(item)
        item.add_child(Node.u32('item_type', itemtype))
        item.add_child(Node.u32('item_id', itemid))
        item.add_child(Node.u32('param', param))
        item.add_child(Node.u32('price', price))

        # Swap with server
        resp = self.exchange('', call)

        # Verify that response is correct
        self.assert_path(resp, "response/game_3/gamecoin_packet")
        self.assert_path(resp, "response/game_3/gamecoin_block")
        self.assert_path(resp, "response/game_3/result")

        if success:
            if resp.child_value('game_3/result') != 0:
                raise Exception('Failed to purchase!')
        else:
            if resp.child_value('game_3/result') == 0:
                raise Exception('Purchased when shouldn\'t have!')
Exemple #28
0
 def handle_player_delete_request(self, request: Node) -> Node:
     return Node.void('player')
Exemple #29
0
    def verify_game_entry_s(self) -> int:
        call = self.call_node()

        game = Node.void('game_3')
        call.add_child(game)
        game.set_attribute('ver', '0')
        game.set_attribute('method', 'entry_s')
        game.add_child(Node.u8('c_ver', 101))
        game.add_child(Node.u8('p_num', 1))
        game.add_child(Node.u8('p_rest', 1))
        game.add_child(Node.u8('filter', 1))
        game.add_child(Node.u32('mid', 416))
        game.add_child(Node.u32('sec', 45))
        game.add_child(Node.u16('port', 10007))
        game.add_child(Node.fouru8('gip', [127, 0, 0, 1]))
        game.add_child(Node.fouru8('lip', [10, 0, 5, 73]))
        game.add_child(Node.u8('claim', 0))

        # Swap with server
        resp = self.exchange('', call)

        # Verify that response is correct
        self.assert_path(resp, "response/game_3/entry_id")
        return resp.child_value('game_3/entry_id')
Exemple #30
0
    def verify_log_play(self, extid: int, loc: str,
                        scores: List[Dict[str, int]]) -> None:
        call = self.call_node()

        log = Node.void('log')
        call.add_child(log)
        log.set_attribute('method', 'play')
        log.add_child(Node.s32('uid', extid))
        log.add_child(Node.string('lid', loc))
        play = Node.void('play')
        log.add_child(play)
        play.add_child(Node.s16('stage', len(scores)))
        play.add_child(Node.s32('sec', 700))

        scoreid = 0
        for score in scores:
            rec = Node.void('rec')
            log.add_child(rec)
            rec.add_child(Node.s16('idx', scoreid))
            rec.add_child(Node.s16('mid', score['id']))
            rec.add_child(Node.s16('grade', score['chart']))
            rec.add_child(Node.s16('color', 0))
            rec.add_child(Node.s16('match', 0))
            rec.add_child(Node.s16('res', 0))
            rec.add_child(Node.s16('score', score['score']))
            rec.add_child(Node.s16('mc', score['combo']))
            rec.add_child(Node.s16('jt_jr', 0))
            rec.add_child(Node.s16('jt_ju', 0))
            rec.add_child(Node.s16('jt_gr', 0))
            rec.add_child(Node.s16('jt_gd', 0))
            rec.add_child(Node.s16('jt_ms', score['miss_count']))
            rec.add_child(Node.s32('sec', 200))
            scoreid = scoreid + 1

        # Swap with server
        resp = self.exchange('', call)

        # Verify that response is correct
        self.assert_path(resp, "response/log/@status")