diff --git a/bemani/api/objects/profile.py b/bemani/api/objects/profile.py index 08ff330..84fb0d3 100644 --- a/bemani/api/objects/profile.py +++ b/bemani/api/objects/profile.py @@ -2,18 +2,18 @@ from typing import Any, Dict, List, Set, Tuple from bemani.api.exceptions import APIException from bemani.api.objects.base import BaseObject -from bemani.common import ValidatedDict, GameConstants, APIConstants +from bemani.common import Profile, ValidatedDict, GameConstants, APIConstants from bemani.data import UserID class ProfileObject(BaseObject): - def __format_ddr_profile(self, profile: ValidatedDict, exact: bool) -> Dict[str, Any]: + def __format_ddr_profile(self, profile: Profile, exact: bool) -> Dict[str, Any]: return { 'area': profile.get_int('area', -1) if exact else -1, } - def __format_iidx_profile(self, profile: ValidatedDict, exact: bool) -> Dict[str, Any]: + def __format_iidx_profile(self, profile: Profile, exact: bool) -> Dict[str, Any]: qpro = profile.get_dict('qpro') return { @@ -27,26 +27,26 @@ class ProfileObject(BaseObject): } } - def __format_jubeat_profile(self, profile: ValidatedDict, exact: bool) -> Dict[str, Any]: + def __format_jubeat_profile(self, profile: Profile, exact: bool) -> Dict[str, Any]: return {} - def __format_museca_profile(self, profile: ValidatedDict, exact: bool) -> Dict[str, Any]: + def __format_museca_profile(self, profile: Profile, exact: bool) -> Dict[str, Any]: return {} - def __format_popn_profile(self, profile: ValidatedDict, exact: bool) -> Dict[str, Any]: + def __format_popn_profile(self, profile: Profile, exact: bool) -> Dict[str, Any]: return { 'character': profile.get_int('chara', -1) if exact else -1, } - def __format_reflec_profile(self, profile: ValidatedDict, exact: bool) -> Dict[str, Any]: + def __format_reflec_profile(self, profile: Profile, exact: bool) -> Dict[str, Any]: return { 'icon': profile.get_dict('config').get_int('icon_id', -1) if exact else -1, } - def __format_sdvx_profile(self, profile: ValidatedDict, exact: bool) -> Dict[str, Any]: + def __format_sdvx_profile(self, profile: Profile, exact: bool) -> Dict[str, Any]: return {} - def __format_profile(self, cardids: List[str], profile: ValidatedDict, settings: ValidatedDict, exact: bool) -> Dict[str, Any]: + def __format_profile(self, cardids: List[str], profile: Profile, settings: ValidatedDict, exact: bool) -> Dict[str, Any]: base = { 'name': profile.get_str('name'), 'cards': cardids, @@ -75,7 +75,7 @@ class ProfileObject(BaseObject): def fetch_v1(self, idtype: APIConstants, ids: List[str], params: Dict[str, Any]) -> List[Dict[str, Any]]: # Fetch the profiles - profiles: List[Tuple[UserID, ValidatedDict]] = [] + profiles: List[Tuple[UserID, Profile]] = [] if idtype == APIConstants.ID_TYPE_SERVER: profiles.extend(self.data.local.user.get_all_profiles(self.game, self.version)) elif idtype == APIConstants.ID_TYPE_SONG: diff --git a/bemani/backend/base.py b/bemani/backend/base.py index c27ebd1..de67127 100644 --- a/bemani/backend/base.py +++ b/bemani/backend/base.py @@ -2,7 +2,7 @@ from abc import ABC import traceback from typing import Any, Dict, Iterator, List, Optional, Set, Tuple, Type -from bemani.common import Model, ValidatedDict, GameConstants, Time +from bemani.common import Model, ValidatedDict, Profile, GameConstants, Time from bemani.data import Data, UserID, RemoteUser @@ -248,7 +248,7 @@ class Base(ABC): """ return self.data.local.user.get_profile(self.game, self.version, userid) is not None - def get_profile(self, userid: UserID) -> Optional[ValidatedDict]: + def get_profile(self, userid: UserID) -> Optional[Profile]: """ Return the profile for a user given this game/version on any connected server. @@ -260,7 +260,7 @@ class Base(ABC): """ return self.data.remote.user.get_profile(self.game, self.version, userid) - def get_any_profile(self, userid: UserID) -> ValidatedDict: + def get_any_profile(self, userid: UserID) -> Profile: """ Return ANY profile for a user in a game series. @@ -279,10 +279,15 @@ class Base(ABC): """ profile = self.data.remote.user.get_any_profile(self.game, self.version, userid) if profile is None: - profile = ValidatedDict() + profile = Profile( + self.game, + self.version, + "", + 0, + ) return profile - def get_any_profiles(self, userids: List[UserID]) -> List[Tuple[UserID, ValidatedDict]]: + def get_any_profiles(self, userids: List[UserID]) -> List[Tuple[UserID, Profile]]: """ Does the identical thing to the above function, but takes a list of user IDs to fetch in bulk. @@ -297,11 +302,11 @@ class Base(ABC): userids = list(set(userids)) profiles = self.data.remote.user.get_any_profiles(self.game, self.version, userids) return [ - (userid, profile if profile is not None else ValidatedDict()) + (userid, profile if profile is not None else Profile(self.game, self.version, "", 0)) for (userid, profile) in profiles ] - def put_profile(self, userid: UserID, profile: ValidatedDict) -> None: + def put_profile(self, userid: UserID, profile: Profile) -> None: """ Save a new profile for this user given a game/version. diff --git a/bemani/backend/bishi/bishi.py b/bemani/backend/bishi/bishi.py index c9856f9..3feb528 100644 --- a/bemani/backend/bishi/bishi.py +++ b/bemani/backend/bishi/bishi.py @@ -7,7 +7,7 @@ from typing import Any, Dict, List, Sequence, Union from bemani.backend.bishi.base import BishiBashiBase from bemani.backend.ess import EventLogHandler -from bemani.common import ValidatedDict, GameConstants, VersionConstants, Time +from bemani.common import Profile, GameConstants, VersionConstants, Time from bemani.data import UserID from bemani.protocol import Node @@ -215,7 +215,7 @@ class TheStarBishiBashi( oldprofile = self.get_profile(userid) is_new = False if oldprofile is None: - oldprofile = ValidatedDict() + oldprofile = Profile(self.game, self.version, refid, 0) is_new = True newprofile = self.unformat_profile(userid, request, oldprofile, is_new) @@ -244,7 +244,7 @@ class TheStarBishiBashi( root.add_child(Node.s32('result', 1)) # Unclear if this is the right thing to do here. return root - def format_profile(self, userid: UserID, profiletype: str, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profiletype: str, profile: Profile) -> Node: root = Node.void('playerdata') root.add_child(Node.s32('result', 0)) player = Node.void('player') @@ -321,7 +321,7 @@ class TheStarBishiBashi( player.add_child(Node.u32('record_num', records)) return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict, is_new: bool) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile, is_new: bool) -> Profile: # Profile save request, data values are base64 encoded. # d is a CSV, and bin1 is binary data. newprofile = copy.deepcopy(oldprofile) diff --git a/bemani/backend/ddr/base.py b/bemani/backend/ddr/base.py index 14ef17e..477b691 100644 --- a/bemani/backend/ddr/base.py +++ b/bemani/backend/ddr/base.py @@ -3,7 +3,7 @@ from typing import Optional, Dict, List, Any from bemani.backend.base import Base from bemani.backend.core import CoreHandler, CardManagerHandler, PASELIHandler -from bemani.common import Model, ValidatedDict, GameConstants, DBConstants, Time +from bemani.common import Model, Profile, ValidatedDict, GameConstants, DBConstants, Time from bemani.data import Data, Score, UserID, ScoreSaveException from bemani.protocol import Node @@ -115,21 +115,21 @@ class DDRBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): """ return None - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> 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') - def format_scores(self, userid: UserID, profile: ValidatedDict, scores: List[Score]) -> Node: + def format_scores(self, userid: UserID, profile: Profile, scores: List[Score]) -> Node: """ Base handler for a score list. Given a userid, profile and a score list, return a Node representing a score list. Should be overridden. """ return Node.void('game') - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: """ Base handler for profile parsing. Given a request and an old profile, return a new profile that's been updated with the contents of the request. @@ -165,10 +165,16 @@ class DDRBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): if userid is None: return - defaultprofile = ValidatedDict({ - 'name': name, - 'area': area, - }) + defaultprofile = Profile( + self.game, + self.version, + refid, + 0, + { + 'name': name, + 'area': area, + }, + ) self.put_profile(userid, defaultprofile) def put_profile_by_refid(self, refid: Optional[str], request: Node) -> None: diff --git a/bemani/backend/ddr/common.py b/bemani/backend/ddr/common.py index de54fa5..fada83e 100644 --- a/bemani/backend/ddr/common.py +++ b/bemani/backend/ddr/common.py @@ -1,7 +1,7 @@ from typing import Dict, Optional, Tuple from bemani.backend.ddr.base import DDRBase -from bemani.common import Time, ValidatedDict, intish +from bemani.common import Time, Profile, intish from bemani.data import Score, UserID from bemani.protocol import Node @@ -98,7 +98,7 @@ class DDRGameHiscoreHandler(DDRBase): typenode.add_child(Node.u16('area', users[userid].get_int('area', 51))) typenode.add_child(Node.u8('rank', gamerank)) typenode.add_child(Node.u8('combo_type', combo_type)) - typenode.add_child(Node.u32('code', users[userid].get_int('extid'))) + typenode.add_child(Node.u32('code', users[userid].extid)) return game @@ -154,7 +154,7 @@ class DDRGameAreaHiscoreHandler(DDRBase): typenode.add_child(Node.u16('area', area_users[userid].get_int('area', 51))) typenode.add_child(Node.u8('rank', gamerank)) typenode.add_child(Node.u8('combo_type', combo_type)) - typenode.add_child(Node.u32('code', area_users[userid].get_int('extid'))) + typenode.add_child(Node.u32('code', area_users[userid].extid)) return game @@ -303,7 +303,7 @@ class DDRGameOldHandler(DDRBase): userid = self.data.remote.user.from_refid(self.game, self.version, refid) previous_version: Optional[DDRBase] = None - oldprofile: Optional[ValidatedDict] = None + oldprofile: Optional[Profile] = None if userid is not None: previous_version = self.previous_version() @@ -362,7 +362,7 @@ class DDRGameFriendHandler(DDRBase): game = Node.void('game') game.set_attribute('data', '1') - game.add_child(Node.u32('code', friend.get_int('extid'))) + game.add_child(Node.u32('code', friend.extid)) game.add_child(Node.string('name', friend.get_str('name'))) game.add_child(Node.u8('area', friend.get_int('area', 51))) game.add_child(Node.u32('exp', play_stats.get_int('exp'))) diff --git a/bemani/backend/ddr/ddr2013.py b/bemani/backend/ddr/ddr2013.py index d60ad2a..188888b 100644 --- a/bemani/backend/ddr/ddr2013.py +++ b/bemani/backend/ddr/ddr2013.py @@ -25,7 +25,7 @@ from bemani.backend.ddr.common import ( DDRGameTaxInfoHandler, DDRGameTraceHandler, ) -from bemani.common import VersionConstants, ValidatedDict, Time, intish +from bemani.common import VersionConstants, Profile, Time, intish from bemani.data import Score, UserID from bemani.protocol import Node @@ -271,7 +271,7 @@ class DDR2013( game = Node.void('game') return game - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: root = Node.void('game') # Look up play stats we bridge to every mix @@ -279,7 +279,7 @@ class DDR2013( # Basic game settings root.add_child(Node.string('seq', '')) - root.add_child(Node.u32('code', profile.get_int('extid'))) + root.add_child(Node.u32('code', profile.extid)) root.add_child(Node.string('name', profile.get_str('name'))) root.add_child(Node.u8('area', profile.get_int('area', 51))) root.add_child(Node.u32('cnt_s', play_stats.get_int('single_plays'))) @@ -424,7 +424,7 @@ class DDR2013( friendnode.set_attribute('pos', str(pos)) friendnode.set_attribute('vs', '0') friendnode.set_attribute('up', '0') - friendnode.add_child(Node.u32('code', friend.get_int('extid'))) + friendnode.add_child(Node.u32('code', friend.extid)) friendnode.add_child(Node.string('name', friend.get_str('name'))) friendnode.add_child(Node.u8('area', friend.get_int('area', 51))) friendnode.add_child(Node.u32('exp', play_stats.get_int('exp'))) @@ -477,7 +477,7 @@ class DDR2013( return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) play_stats = self.get_play_statistics(userid) diff --git a/bemani/backend/ddr/ddr2014.py b/bemani/backend/ddr/ddr2014.py index 1aaae50..b700988 100644 --- a/bemani/backend/ddr/ddr2014.py +++ b/bemani/backend/ddr/ddr2014.py @@ -22,7 +22,7 @@ from bemani.backend.ddr.common import ( DDRGameShopHandler, DDRGameTaxInfoHandler, ) -from bemani.common import VersionConstants, ValidatedDict, Time, intish +from bemani.common import VersionConstants, Profile, Time, intish from bemani.data import Score, UserID from bemani.protocol import Node @@ -321,7 +321,7 @@ class DDR2014( return game - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: root = Node.void('game') # Look up play stats we bridge to every mix @@ -329,7 +329,7 @@ class DDR2014( # Basic game settings root.add_child(Node.string('seq', '')) - root.add_child(Node.u32('code', profile.get_int('extid'))) + root.add_child(Node.u32('code', profile.extid)) root.add_child(Node.string('name', profile.get_str('name'))) root.add_child(Node.u8('area', profile.get_int('area', 51))) root.add_child(Node.u32('cnt_s', play_stats.get_int('single_plays'))) @@ -479,7 +479,7 @@ class DDR2014( friendnode.set_attribute('pos', str(pos)) friendnode.set_attribute('vs', '0') friendnode.set_attribute('up', '0') - friendnode.add_child(Node.u32('code', friend.get_int('extid'))) + friendnode.add_child(Node.u32('code', friend.extid)) friendnode.add_child(Node.string('name', friend.get_str('name'))) friendnode.add_child(Node.u8('area', friend.get_int('area', 51))) friendnode.add_child(Node.u32('exp', play_stats.get_int('exp'))) @@ -538,7 +538,7 @@ class DDR2014( return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) play_stats = self.get_play_statistics(userid) diff --git a/bemani/backend/ddr/ddrace.py b/bemani/backend/ddr/ddrace.py index e3eb9f3..9285ca5 100644 --- a/bemani/backend/ddr/ddrace.py +++ b/bemani/backend/ddr/ddrace.py @@ -5,7 +5,7 @@ from typing import Dict, List, Optional from bemani.backend.ess import EventLogHandler from bemani.backend.ddr.base import DDRBase from bemani.backend.ddr.ddr2014 import DDR2014 -from bemani.common import ValidatedDict, VersionConstants, CardCipher, Time, ID, intish +from bemani.common import Profile, ValidatedDict, VersionConstants, CardCipher, Time, ID, intish from bemani.data import Achievement, Machine, Score, UserID from bemani.protocol import Node @@ -470,7 +470,7 @@ class DDRAce( machines_by_id: Dict[int, Optional[Machine]] = {thismachine.id: thismachine} loadkind = requestdata.child_value('loadflag') - profiles_by_userid: Dict[UserID, ValidatedDict] = {} + profiles_by_userid: Dict[UserID, Profile] = {} def get_machine(lid: int) -> Optional[Machine]: if lid not in machines_by_id: @@ -551,7 +551,7 @@ class DDRAce( 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('code', profiledata.extid)) record.add_child(Node.s32('score', score.points)) record.add_child(Node.s32('ghostid', score.key)) @@ -560,13 +560,19 @@ class DDRAce( raise Exception('Expecting valid UserID to create new profile!') machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) - self.put_profile(userid, ValidatedDict({ - 'lid': machine.id, - })) - profile = self.get_profile(userid) + profile = Profile( + self.game, + self.version, + "", + 0, + { + 'lid': machine.id, + }, + ) + self.put_profile(userid, profile) - response.add_child(Node.string('seq', ID.format_extid(profile.get_int('extid')))) - response.add_child(Node.s32('code', profile.get_int('extid'))) + response.add_child(Node.string('seq', ID.format_extid(profile.extid))) + response.add_child(Node.s32('code', profile.extid)) response.add_child(Node.string('shoparea', '')) def __handle_inheritance(self, userid: Optional[UserID], requestdata: Node, response: Node) -> None: @@ -588,7 +594,7 @@ class DDRAce( ghostdata = Node.void('ghostdata') response.add_child(ghostdata) - ghostdata.add_child(Node.s32('code', profile.get_int('extid'))) + ghostdata.add_child(Node.s32('code', profile.extid)) ghostdata.add_child(Node.u32('mcode', score.id)) ghostdata.add_child(Node.u8('notetype', self.db_to_game_chart(score.chart))) ghostdata.add_child(Node.s32('ghostsize', len(score.data['ghost']))) @@ -632,7 +638,7 @@ class DDRAce( userid = self.data.remote.user.from_refid(self.game, self.version, refid) if userid is not None: - profile = self.get_profile(userid) or ValidatedDict() + profile = self.get_profile(userid) or Profile(self.game, self.version, refid, 0) usergamedata = profile.get_dict('usergamedata') for record in request.child('data/record').children: @@ -741,7 +747,7 @@ class DDRAce( rival = usergamedata[ptype]['strdata'].split(b',') lastdict = profile.get_dict('last') - friends: Dict[int, Optional[ValidatedDict]] = {} + friends: Dict[int, Optional[Profile]] = {} for link in links: if link.type[:7] != 'friend_': continue @@ -775,7 +781,7 @@ class DDRAce( }[rivalno] rival[activeslot] = acehex(rivalno).encode('ascii') - rival[ddrcodeslot] = acehex(friendprofile.get_int('extid')).encode('ascii') + rival[ddrcodeslot] = acehex(friendprofile.extid).encode('ascii') usergamedata[ptype]['strdata'] = b','.join(rival) diff --git a/bemani/backend/ddr/ddrx2.py b/bemani/backend/ddr/ddrx2.py index af2e4ca..53dc801 100644 --- a/bemani/backend/ddr/ddrx2.py +++ b/bemani/backend/ddr/ddrx2.py @@ -20,7 +20,7 @@ from bemani.backend.ddr.common import ( DDRGameShopHandler, DDRGameTraceHandler, ) -from bemani.common import Time, VersionConstants, ValidatedDict, intish +from bemani.common import Time, VersionConstants, Profile, intish from bemani.data import Score, UserID from bemani.protocol import Node @@ -297,7 +297,7 @@ class DDRX2( game = Node.void('game') return game - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: root = Node.void('game') # Look up play stats we bridge to every mix @@ -305,7 +305,7 @@ class DDRX2( # Basic game settings root.add_child(Node.string('seq', '')) - root.add_child(Node.u32('code', profile.get_int('extid'))) + root.add_child(Node.u32('code', profile.extid)) root.add_child(Node.string('name', profile.get_str('name'))) root.add_child(Node.u8('area', profile.get_int('area', 51))) root.add_child(Node.u32('cnt_s', play_stats.get_int('single_plays'))) @@ -470,7 +470,7 @@ class DDRX2( friendnode.set_attribute('pos', str(pos)) friendnode.set_attribute('vs', '0') friendnode.set_attribute('up', '0') - friendnode.add_child(Node.u32('code', friend.get_int('extid'))) + friendnode.add_child(Node.u32('code', friend.extid)) friendnode.add_child(Node.string('name', friend.get_str('name'))) friendnode.add_child(Node.u8('area', friend.get_int('area', 51))) friendnode.add_child(Node.u32('exp', play_stats.get_int('exp'))) @@ -516,7 +516,7 @@ class DDRX2( return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) play_stats = self.get_play_statistics(userid) diff --git a/bemani/backend/ddr/ddrx3.py b/bemani/backend/ddr/ddrx3.py index fa8451b..9475d4a 100644 --- a/bemani/backend/ddr/ddrx3.py +++ b/bemani/backend/ddr/ddrx3.py @@ -23,7 +23,7 @@ from bemani.backend.ddr.common import ( DDRGameShopHandler, DDRGameTraceHandler, ) -from bemani.common import ValidatedDict, VersionConstants, Time, intish +from bemani.common import Profile, VersionConstants, Time, intish from bemani.data import Achievement, Score, UserID from bemani.protocol import Node @@ -346,7 +346,7 @@ class DDRX3( game = Node.void('game') return game - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: root = Node.void('game') # Look up play stats we bridge to every mix @@ -354,7 +354,7 @@ class DDRX3( # Basic game settings root.add_child(Node.string('seq', '')) - root.add_child(Node.u32('code', profile.get_int('extid'))) + root.add_child(Node.u32('code', profile.extid)) root.add_child(Node.string('name', profile.get_str('name'))) root.add_child(Node.u8('area', profile.get_int('area', 51))) root.add_child(Node.u32('cnt_s', play_stats.get_int('single_plays'))) @@ -499,7 +499,7 @@ class DDRX3( friendnode.set_attribute('pos', str(pos)) friendnode.set_attribute('vs', '0') friendnode.set_attribute('up', '0') - friendnode.add_child(Node.u32('code', friend.get_int('extid'))) + friendnode.add_child(Node.u32('code', friend.extid)) friendnode.add_child(Node.string('name', friend.get_str('name'))) friendnode.add_child(Node.u8('area', friend.get_int('area', 51))) friendnode.add_child(Node.u32('exp', play_stats.get_int('exp'))) @@ -552,7 +552,7 @@ class DDRX3( return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) play_stats = self.get_play_statistics(userid) diff --git a/bemani/backend/iidx/base.py b/bemani/backend/iidx/base.py index 9df1a04..c8fde56 100644 --- a/bemani/backend/iidx/base.py +++ b/bemani/backend/iidx/base.py @@ -4,7 +4,7 @@ from typing import Optional, Dict, Any, List, Tuple from bemani.backend.base import Base from bemani.backend.core import CoreHandler, CardManagerHandler, PASELIHandler -from bemani.common import ValidatedDict, Model, GameConstants, DBConstants, Parallel +from bemani.common import Profile, ValidatedDict, Model, GameConstants, DBConstants, Parallel from bemani.data import Data, Score, Machine, UserID from bemani.protocol import Node @@ -103,14 +103,14 @@ class IIDXBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): 'local2', ] - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> 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('pc') - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: """ Base handler for profile parsing. Given a request and an old profile, return a new profile that's been updated with the contents of the request. @@ -138,7 +138,7 @@ class IIDXBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): return None return self.format_profile(userid, profile) - def new_profile_by_refid(self, refid: Optional[str], name: Optional[str], pid: Optional[int]) -> ValidatedDict: + def new_profile_by_refid(self, refid: Optional[str], name: Optional[str], pid: Optional[int]) -> Profile: """ Given a RefID and an optional name, create a profile and then return that newly created profile. @@ -152,15 +152,20 @@ class IIDXBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): pid = 51 userid = self.data.remote.user.from_refid(self.game, self.version, refid) - defaultprofile = ValidatedDict({ - 'name': name, - 'pid': pid, - 'settings': { - 'flags': 223 # Default to turning on all optional folders + profile = Profile( + self.game, + self.version, + refid, + 0, + { + 'name': name, + 'pid': pid, + 'settings': { + 'flags': 223 # Default to turning on all optional folders + }, }, - }) - self.put_profile(userid, defaultprofile) - profile = self.get_profile(userid) + ) + self.put_profile(userid, profile) return profile def put_profile_by_extid(self, extid: Optional[int], request: Node) -> None: @@ -454,7 +459,12 @@ class IIDXBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): # Update profile if needed profile = self.get_profile(userid) if profile is None: - profile = ValidatedDict() + profile = Profile( + self.game, + self.version, + "", + 0, + ) profile.replace_int(dantype, max(rank, profile.get_int(dantype, -1))) self.put_profile(userid, profile) @@ -606,7 +616,7 @@ class IIDXBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): # Return averages return new_ex_score, struct.pack('b' * ghost_length, *delta_ghost) - def user_joined_arcade(self, machine: Machine, profile: Optional[ValidatedDict]) -> bool: + def user_joined_arcade(self, machine: Machine, profile: Optional[Profile]) -> bool: if profile is None: return False @@ -671,7 +681,12 @@ class IIDXBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): # other users who have also joined that arcade. my_profile = self.get_profile(userid) if my_profile is None: - my_profile = ValidatedDict() + my_profile = Profile( + self.game, + self.version, + "", + 0, + ) if 'shop_location' in my_profile: shop_id = my_profile.get_int('shop_location') @@ -708,7 +723,7 @@ class IIDXBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): 'ghost': top_score.data.get_bytes('ghost'), 'name': top_profile.get_str('name'), 'pid': top_profile.get_int('pid'), - 'extid': top_profile.get_int('extid'), + 'extid': top_profile.extid, } break @@ -734,7 +749,12 @@ class IIDXBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): ] my_profile = self.get_profile(userid) if my_profile is None: - my_profile = ValidatedDict() + my_profile = Profile( + self.game, + self.version, + "", + 0, + ) if is_dp: dan_rank = my_profile.get_int(self.DAN_RANKING_DOUBLE, -1) else: @@ -766,7 +786,7 @@ class IIDXBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): 'ghost': top_score.data.get_bytes('ghost'), 'name': top_profile.get_str('name'), 'pid': top_profile.get_int('pid'), - 'extid': top_profile.get_int('extid'), + 'extid': top_profile.extid, } break @@ -808,7 +828,7 @@ class IIDXBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): 'ghost': top_score.data.get_bytes('ghost'), 'name': top_profile.get_str('name'), 'pid': top_profile.get_int('pid'), - 'extid': top_profile.get_int('extid'), + 'extid': top_profile.extid, } break diff --git a/bemani/backend/iidx/cannonballers.py b/bemani/backend/iidx/cannonballers.py index 9e4d178..3b7ef3c 100644 --- a/bemani/backend/iidx/cannonballers.py +++ b/bemani/backend/iidx/cannonballers.py @@ -8,7 +8,7 @@ from bemani.backend.iidx.base import IIDXBase from bemani.backend.iidx.course import IIDXCourse from bemani.backend.iidx.sinobuz import IIDXSinobuz -from bemani.common import ValidatedDict, VersionConstants, BroadcastConstants, Time, ID, intish +from bemani.common import Profile, ValidatedDict, VersionConstants, BroadcastConstants, Time, ID, intish from bemani.data import Data, UserID from bemani.protocol import Node @@ -404,7 +404,7 @@ class IIDXCannonBallers(IIDXCourse, IIDXBase): ] totalscores: Dict[UserID, int] = {} - profiles: Dict[UserID, ValidatedDict] = {} + profiles: Dict[UserID, Profile] = {} for songid in songids: scores = self.data.local.music.get_all_scores( self.game, @@ -421,7 +421,7 @@ class IIDXCannonBallers(IIDXCourse, IIDXBase): totalscores[score[0]] = 0 profile = self.get_any_profile(score[0]) if profile is None: - profile = ValidatedDict() + profile = Profile(self.game, self.version, "", 0) profiles[score[0]] = profile totalscores[score[0]] += score[1].points @@ -802,7 +802,7 @@ class IIDXCannonBallers(IIDXCourse, IIDXBase): data = Node.void('data') ranklist.add_child(data) - data.set_attribute('iidx_id', str(profile.get_int('extid'))) + data.set_attribute('iidx_id', str(profile.extid)) data.set_attribute('name', profile.get_str('name')) machine_name = '' @@ -1257,7 +1257,7 @@ class IIDXCannonBallers(IIDXCourse, IIDXBase): root = Node.void('IIDX25pc') root.set_attribute('name', profile.get_str('name')) - root.set_attribute('idstr', ID.format_extid(profile.get_int('extid'))) + root.set_attribute('idstr', ID.format_extid(profile.extid)) root.set_attribute('pid', str(profile.get_int('pid'))) return root @@ -1269,7 +1269,7 @@ class IIDXCannonBallers(IIDXCourse, IIDXBase): root = Node.void('IIDX25pc') if newprofile is not None: - root.set_attribute('id', str(newprofile.get_int('extid'))) + root.set_attribute('id', str(newprofile.extid)) return root def handle_IIDX25pc_reg_request(self, request: Node) -> Node: @@ -1280,8 +1280,8 @@ class IIDXCannonBallers(IIDXCourse, IIDXBase): root = Node.void('IIDX25pc') if profile is not None: - root.set_attribute('id', str(profile.get_int('extid'))) - root.set_attribute('id_str', ID.format_extid(profile.get_int('extid'))) + root.set_attribute('id', str(profile.extid)) + root.set_attribute('id_str', ID.format_extid(profile.extid)) return root def handle_IIDX25pc_get_request(self, request: Node) -> Node: @@ -1417,7 +1417,7 @@ class IIDXCannonBallers(IIDXCourse, IIDXBase): return Node.void('IIDX25pc') - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: root = Node.void('IIDX25pc') # Look up play stats we bridge to every mix @@ -1430,8 +1430,8 @@ class IIDXCannonBallers(IIDXCourse, IIDXBase): # Profile data pcdata = Node.void('pcdata') root.add_child(pcdata) - pcdata.set_attribute('id', str(profile.get_int('extid'))) - pcdata.set_attribute('idstr', ID.format_extid(profile.get_int('extid'))) + pcdata.set_attribute('id', str(profile.extid)) + pcdata.set_attribute('idstr', ID.format_extid(profile.extid)) pcdata.set_attribute('name', profile.get_str('name')) pcdata.set_attribute('pid', str(profile.get_int('pid'))) pcdata.set_attribute('spnum', str(play_stats.get_int('single_plays'))) @@ -1636,8 +1636,8 @@ class IIDXCannonBallers(IIDXCourse, IIDXBase): rival = Node.void('rival') rlist.add_child(rival) rival.set_attribute('spdp', rival_type) - rival.set_attribute('id', str(other_profile.get_int('extid'))) - rival.set_attribute('id_str', ID.format_extid(other_profile.get_int('extid'))) + rival.set_attribute('id', str(other_profile.extid)) + rival.set_attribute('id_str', ID.format_extid(other_profile.extid)) rival.set_attribute('djname', other_profile.get_str('name')) rival.set_attribute('pid', str(other_profile.get_int('pid'))) rival.set_attribute('sg', str(self.db_to_game_rank(other_profile.get_int(self.DAN_RANKING_SINGLE, -1), self.GAME_CLTYPE_SINGLE))) @@ -1860,7 +1860,7 @@ class IIDXCannonBallers(IIDXCourse, IIDXBase): pay_per_use.set_attribute('item_num', '99') return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) play_stats = self.get_play_statistics(userid) diff --git a/bemani/backend/iidx/copula.py b/bemani/backend/iidx/copula.py index a7249e2..4ad56d2 100644 --- a/bemani/backend/iidx/copula.py +++ b/bemani/backend/iidx/copula.py @@ -8,7 +8,7 @@ from bemani.backend.iidx.base import IIDXBase from bemani.backend.iidx.course import IIDXCourse from bemani.backend.iidx.pendual import IIDXPendual -from bemani.common import ValidatedDict, VersionConstants, BroadcastConstants, Time, ID +from bemani.common import Profile, ValidatedDict, VersionConstants, BroadcastConstants, Time, ID from bemani.data import Data, UserID from bemani.protocol import Node @@ -392,7 +392,7 @@ class IIDXCopula(IIDXCourse, IIDXBase): ] totalscores: Dict[UserID, int] = {} - profiles: Dict[UserID, ValidatedDict] = {} + profiles: Dict[UserID, Profile] = {} for songid in songids: scores = self.data.local.music.get_all_scores( self.game, @@ -406,7 +406,7 @@ class IIDXCopula(IIDXCourse, IIDXBase): totalscores[score[0]] = 0 profile = self.get_any_profile(score[0]) if profile is None: - profile = ValidatedDict() + profile = Profile(self.game, self.version, "", 0) profiles[score[0]] = profile totalscores[score[0]] += score[1].points @@ -695,7 +695,7 @@ class IIDXCopula(IIDXCourse, IIDXBase): data = Node.void('data') ranklist.add_child(data) - data.set_attribute('iidx_id', str(profile.get_int('extid'))) + data.set_attribute('iidx_id', str(profile.extid)) data.set_attribute('name', profile.get_str('name')) machine_name = '' @@ -1320,7 +1320,7 @@ class IIDXCopula(IIDXCourse, IIDXBase): root = Node.void('IIDX23pc') root.set_attribute('name', profile.get_str('name')) - root.set_attribute('idstr', ID.format_extid(profile.get_int('extid'))) + root.set_attribute('idstr', ID.format_extid(profile.extid)) root.set_attribute('pid', str(profile.get_int('pid'))) return root @@ -1332,7 +1332,7 @@ class IIDXCopula(IIDXCourse, IIDXBase): root = Node.void('IIDX23pc') if newprofile is not None: - root.set_attribute('id', str(newprofile.get_int('extid'))) + root.set_attribute('id', str(newprofile.extid)) return root if method == 'reg': @@ -1343,8 +1343,8 @@ class IIDXCopula(IIDXCourse, IIDXBase): root = Node.void('IIDX23pc') if profile is not None: - root.set_attribute('id', str(profile.get_int('extid'))) - root.set_attribute('id_str', ID.format_extid(profile.get_int('extid'))) + root.set_attribute('id', str(profile.extid)) + root.set_attribute('id_str', ID.format_extid(profile.extid)) return root if method == 'get': @@ -1379,7 +1379,7 @@ class IIDXCopula(IIDXCourse, IIDXBase): if userid is not None: profile = self.get_profile(userid) if profile is None: - profile = ValidatedDict() + profile = Profile(self.game, self.version, "", extid) profile.replace_int('shop_location', location) self.put_profile(userid, profile) @@ -1469,7 +1469,7 @@ class IIDXCopula(IIDXCourse, IIDXBase): return Node.void('IIDX23pc') - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: root = Node.void('IIDX23pc') # Look up play stats we bridge to every mix @@ -1482,8 +1482,8 @@ class IIDXCopula(IIDXCourse, IIDXBase): # Profile data pcdata = Node.void('pcdata') root.add_child(pcdata) - pcdata.set_attribute('id', str(profile.get_int('extid'))) - pcdata.set_attribute('idstr', ID.format_extid(profile.get_int('extid'))) + pcdata.set_attribute('id', str(profile.extid)) + pcdata.set_attribute('idstr', ID.format_extid(profile.extid)) pcdata.set_attribute('name', profile.get_str('name')) pcdata.set_attribute('pid', str(profile.get_int('pid'))) pcdata.set_attribute('spnum', str(play_stats.get_int('single_plays'))) @@ -1660,8 +1660,8 @@ class IIDXCopula(IIDXCourse, IIDXBase): rival = Node.void('rival') rlist.add_child(rival) rival.set_attribute('spdp', rival_type) - rival.set_attribute('id', str(other_profile.get_int('extid'))) - rival.set_attribute('id_str', ID.format_extid(other_profile.get_int('extid'))) + rival.set_attribute('id', str(other_profile.extid)) + rival.set_attribute('id_str', ID.format_extid(other_profile.extid)) rival.set_attribute('djname', other_profile.get_str('name')) rival.set_attribute('pid', str(other_profile.get_int('pid'))) rival.set_attribute('sg', str(self.db_to_game_rank(other_profile.get_int(self.DAN_RANKING_SINGLE, -1), self.GAME_CLTYPE_SINGLE))) @@ -1869,7 +1869,7 @@ class IIDXCopula(IIDXCourse, IIDXBase): root.add_child(Node.void('bind_eaappli')) return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) play_stats = self.get_play_statistics(userid) diff --git a/bemani/backend/iidx/pendual.py b/bemani/backend/iidx/pendual.py index ef3a34a..90fe1e1 100644 --- a/bemani/backend/iidx/pendual.py +++ b/bemani/backend/iidx/pendual.py @@ -8,7 +8,7 @@ from bemani.backend.iidx.base import IIDXBase from bemani.backend.iidx.course import IIDXCourse from bemani.backend.iidx.spada import IIDXSpada -from bemani.common import ValidatedDict, VersionConstants, BroadcastConstants, Time, ID +from bemani.common import Profile, ValidatedDict, VersionConstants, BroadcastConstants, Time, ID from bemani.data import Data, UserID from bemani.protocol import Node @@ -255,7 +255,7 @@ class IIDXPendual(IIDXCourse, IIDXBase): ] totalscores: Dict[UserID, int] = {} - profiles: Dict[UserID, ValidatedDict] = {} + profiles: Dict[UserID, Profile] = {} for songid in songids: scores = self.data.local.music.get_all_scores( self.game, @@ -269,7 +269,7 @@ class IIDXPendual(IIDXCourse, IIDXBase): totalscores[score[0]] = 0 profile = self.get_any_profile(score[0]) if profile is None: - profile = ValidatedDict() + profile = Profile(self.game, self.version, "", 0) profiles[score[0]] = profile totalscores[score[0]] += score[1].points @@ -679,7 +679,7 @@ class IIDXPendual(IIDXCourse, IIDXBase): data = Node.void('data') ranklist.add_child(data) - data.set_attribute('iidx_id', str(profile.get_int('extid'))) + data.set_attribute('iidx_id', str(profile.extid)) data.set_attribute('name', profile.get_str('name')) machine_name = '' @@ -1233,7 +1233,7 @@ class IIDXPendual(IIDXCourse, IIDXBase): root = Node.void('IIDX22pc') root.set_attribute('name', profile.get_str('name')) - root.set_attribute('idstr', ID.format_extid(profile.get_int('extid'))) + root.set_attribute('idstr', ID.format_extid(profile.extid)) root.set_attribute('pid', str(profile.get_int('pid'))) return root @@ -1245,7 +1245,7 @@ class IIDXPendual(IIDXCourse, IIDXBase): root = Node.void('IIDX22pc') if newprofile is not None: - root.set_attribute('id', str(newprofile.get_int('extid'))) + root.set_attribute('id', str(newprofile.extid)) return root if method == 'reg': @@ -1256,8 +1256,8 @@ class IIDXPendual(IIDXCourse, IIDXBase): root = Node.void('IIDX22pc') if profile is not None: - root.set_attribute('id', str(profile.get_int('extid'))) - root.set_attribute('id_str', ID.format_extid(profile.get_int('extid'))) + root.set_attribute('id', str(profile.extid)) + root.set_attribute('id_str', ID.format_extid(profile.extid)) return root if method == 'get': @@ -1292,7 +1292,7 @@ class IIDXPendual(IIDXCourse, IIDXBase): if userid is not None: profile = self.get_profile(userid) if profile is None: - profile = ValidatedDict() + profile = Profile(self.game, self.version, "", extid) profile.replace_int('shop_location', location) self.put_profile(userid, profile) @@ -1382,7 +1382,7 @@ class IIDXPendual(IIDXCourse, IIDXBase): return Node.void('IIDX22pc') - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: root = Node.void('IIDX22pc') # Look up play stats we bridge to every mix @@ -1395,8 +1395,8 @@ class IIDXPendual(IIDXCourse, IIDXBase): # Profile data pcdata = Node.void('pcdata') root.add_child(pcdata) - pcdata.set_attribute('id', str(profile.get_int('extid'))) - pcdata.set_attribute('idstr', ID.format_extid(profile.get_int('extid'))) + pcdata.set_attribute('id', str(profile.extid)) + pcdata.set_attribute('idstr', ID.format_extid(profile.extid)) pcdata.set_attribute('name', profile.get_str('name')) pcdata.set_attribute('pid', str(profile.get_int('pid'))) pcdata.set_attribute('spnum', str(play_stats.get_int('single_plays'))) @@ -1628,8 +1628,8 @@ class IIDXPendual(IIDXCourse, IIDXBase): rival = Node.void('rival') rlist.add_child(rival) rival.set_attribute('spdp', rival_type) - rival.set_attribute('id', str(other_profile.get_int('extid'))) - rival.set_attribute('id_str', ID.format_extid(other_profile.get_int('extid'))) + rival.set_attribute('id', str(other_profile.extid)) + rival.set_attribute('id_str', ID.format_extid(other_profile.extid)) rival.set_attribute('djname', other_profile.get_str('name')) rival.set_attribute('pid', str(other_profile.get_int('pid'))) rival.set_attribute('sg', str(self.db_to_game_rank(other_profile.get_int(self.DAN_RANKING_SINGLE, -1), self.GAME_CLTYPE_SINGLE))) @@ -1715,7 +1715,7 @@ class IIDXPendual(IIDXCourse, IIDXBase): root.add_child(Node.void('bind_eaappli')) return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) play_stats = self.get_play_statistics(userid) diff --git a/bemani/backend/iidx/rootage.py b/bemani/backend/iidx/rootage.py index c863519..80cad5b 100644 --- a/bemani/backend/iidx/rootage.py +++ b/bemani/backend/iidx/rootage.py @@ -8,7 +8,7 @@ from bemani.backend.iidx.base import IIDXBase from bemani.backend.iidx.course import IIDXCourse from bemani.backend.iidx.cannonballers import IIDXCannonBallers -from bemani.common import ValidatedDict, VersionConstants, BroadcastConstants, Time, ID, intish +from bemani.common import Profile, ValidatedDict, VersionConstants, BroadcastConstants, Time, ID, intish from bemani.data import Data, UserID from bemani.protocol import Node @@ -655,7 +655,7 @@ class IIDXRootage(IIDXCourse, IIDXBase): data = Node.void('data') ranklist.add_child(data) - data.set_attribute('iidx_id', str(profile.get_int('extid'))) + data.set_attribute('iidx_id', str(profile.extid)) data.set_attribute('name', profile.get_str('name')) machine_name = '' @@ -932,7 +932,7 @@ class IIDXRootage(IIDXCourse, IIDXBase): root = Node.void('IIDX26pc') root.set_attribute('name', profile.get_str('name')) - root.set_attribute('idstr', ID.format_extid(profile.get_int('extid'))) + root.set_attribute('idstr', ID.format_extid(profile.extid)) root.set_attribute('pid', str(profile.get_int('pid'))) return root @@ -944,7 +944,7 @@ class IIDXRootage(IIDXCourse, IIDXBase): root = Node.void('IIDX26pc') if newprofile is not None: - root.set_attribute('id', str(newprofile.get_int('extid'))) + root.set_attribute('id', str(newprofile.extid)) return root def handle_IIDX26pc_reg_request(self, request: Node) -> Node: @@ -955,8 +955,8 @@ class IIDXRootage(IIDXCourse, IIDXBase): root = Node.void('IIDX26pc') if profile is not None: - root.set_attribute('id', str(profile.get_int('extid'))) - root.set_attribute('id_str', ID.format_extid(profile.get_int('extid'))) + root.set_attribute('id', str(profile.extid)) + root.set_attribute('id_str', ID.format_extid(profile.extid)) return root def handle_IIDX26pc_get_request(self, request: Node) -> Node: @@ -1092,7 +1092,7 @@ class IIDXRootage(IIDXCourse, IIDXBase): matching_class_range.add_child(Node.s32('high_arena_class', 20)) return root - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: root = Node.void('IIDX26pc') # Look up play stats we bridge to every mix @@ -1105,8 +1105,8 @@ class IIDXRootage(IIDXCourse, IIDXBase): # Profile data pcdata = Node.void('pcdata') root.add_child(pcdata) - pcdata.set_attribute('id', str(profile.get_int('extid'))) - pcdata.set_attribute('idstr', ID.format_extid(profile.get_int('extid'))) + pcdata.set_attribute('id', str(profile.extid)) + pcdata.set_attribute('idstr', ID.format_extid(profile.extid)) pcdata.set_attribute('name', profile.get_str('name')) pcdata.set_attribute('pid', str(profile.get_int('pid'))) pcdata.set_attribute('spnum', str(play_stats.get_int('single_plays'))) @@ -1330,8 +1330,8 @@ class IIDXRootage(IIDXCourse, IIDXBase): rival = Node.void('rival') rlist.add_child(rival) rival.set_attribute('spdp', rival_type) - rival.set_attribute('id', str(other_profile.get_int('extid'))) - rival.set_attribute('id_str', ID.format_extid(other_profile.get_int('extid'))) + rival.set_attribute('id', str(other_profile.extid)) + rival.set_attribute('id_str', ID.format_extid(other_profile.extid)) rival.set_attribute('djname', other_profile.get_str('name')) rival.set_attribute('pid', str(other_profile.get_int('pid'))) rival.set_attribute('sg', str(self.db_to_game_rank(other_profile.get_int(self.DAN_RANKING_SINGLE, -1), self.GAME_CLTYPE_SINGLE))) @@ -1572,7 +1572,7 @@ class IIDXRootage(IIDXCourse, IIDXBase): return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) play_stats = self.get_play_statistics(userid) diff --git a/bemani/backend/iidx/sinobuz.py b/bemani/backend/iidx/sinobuz.py index c9cce7a..2b99228 100644 --- a/bemani/backend/iidx/sinobuz.py +++ b/bemani/backend/iidx/sinobuz.py @@ -8,7 +8,7 @@ from bemani.backend.iidx.base import IIDXBase from bemani.backend.iidx.course import IIDXCourse from bemani.backend.iidx.copula import IIDXCopula -from bemani.common import ValidatedDict, VersionConstants, BroadcastConstants, Time, ID, intish +from bemani.common import Profile, ValidatedDict, VersionConstants, BroadcastConstants, Time, ID, intish from bemani.data import Data, UserID from bemani.protocol import Node @@ -404,7 +404,7 @@ class IIDXSinobuz(IIDXCourse, IIDXBase): ] totalscores: Dict[UserID, int] = {} - profiles: Dict[UserID, ValidatedDict] = {} + profiles: Dict[UserID, Profile] = {} for songid in songids: scores = self.data.local.music.get_all_scores( self.game, @@ -418,7 +418,7 @@ class IIDXSinobuz(IIDXCourse, IIDXBase): totalscores[score[0]] = 0 profile = self.get_any_profile(score[0]) if profile is None: - profile = ValidatedDict() + profile = Profile(self.game, self.version, "", 0) profiles[score[0]] = profile totalscores[score[0]] += score[1].points @@ -799,7 +799,7 @@ class IIDXSinobuz(IIDXCourse, IIDXBase): data = Node.void('data') ranklist.add_child(data) - data.set_attribute('iidx_id', str(profile.get_int('extid'))) + data.set_attribute('iidx_id', str(profile.extid)) data.set_attribute('name', profile.get_str('name')) machine_name = '' @@ -1284,7 +1284,7 @@ class IIDXSinobuz(IIDXCourse, IIDXBase): if userid is not None: profile = self.get_profile(userid) if profile is None: - profile = ValidatedDict() + profile = Profile(self.game, self.version, "", extid) profile.replace_int('shop_location', location) self.put_profile(userid, profile) @@ -1321,7 +1321,7 @@ class IIDXSinobuz(IIDXCourse, IIDXBase): root = Node.void('IIDX24pc') root.set_attribute('name', profile.get_str('name')) - root.set_attribute('idstr', ID.format_extid(profile.get_int('extid'))) + root.set_attribute('idstr', ID.format_extid(profile.extid)) root.set_attribute('pid', str(profile.get_int('pid'))) return root @@ -1333,7 +1333,7 @@ class IIDXSinobuz(IIDXCourse, IIDXBase): root = Node.void('IIDX24pc') if newprofile is not None: - root.set_attribute('id', str(newprofile.get_int('extid'))) + root.set_attribute('id', str(newprofile.extid)) return root def handle_IIDX24pc_reg_request(self, request: Node) -> Node: @@ -1344,8 +1344,8 @@ class IIDXSinobuz(IIDXCourse, IIDXBase): root = Node.void('IIDX24pc') if profile is not None: - root.set_attribute('id', str(profile.get_int('extid'))) - root.set_attribute('id_str', ID.format_extid(profile.get_int('extid'))) + root.set_attribute('id', str(profile.extid)) + root.set_attribute('id_str', ID.format_extid(profile.extid)) return root def handle_IIDX24pc_get_request(self, request: Node) -> Node: @@ -1441,7 +1441,7 @@ class IIDXSinobuz(IIDXCourse, IIDXBase): return Node.void('IIDX24pc') - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: root = Node.void('IIDX24pc') # Look up play stats we bridge to every mix @@ -1454,8 +1454,8 @@ class IIDXSinobuz(IIDXCourse, IIDXBase): # Profile data pcdata = Node.void('pcdata') root.add_child(pcdata) - pcdata.set_attribute('id', str(profile.get_int('extid'))) - pcdata.set_attribute('idstr', ID.format_extid(profile.get_int('extid'))) + pcdata.set_attribute('id', str(profile.extid)) + pcdata.set_attribute('idstr', ID.format_extid(profile.extid)) pcdata.set_attribute('name', profile.get_str('name')) pcdata.set_attribute('pid', str(profile.get_int('pid'))) pcdata.set_attribute('spnum', str(play_stats.get_int('single_plays'))) @@ -1652,8 +1652,8 @@ class IIDXSinobuz(IIDXCourse, IIDXBase): rival = Node.void('rival') rlist.add_child(rival) rival.set_attribute('spdp', rival_type) - rival.set_attribute('id', str(other_profile.get_int('extid'))) - rival.set_attribute('id_str', ID.format_extid(other_profile.get_int('extid'))) + rival.set_attribute('id', str(other_profile.extid)) + rival.set_attribute('id_str', ID.format_extid(other_profile.extid)) rival.set_attribute('djname', other_profile.get_str('name')) rival.set_attribute('pid', str(other_profile.get_int('pid'))) rival.set_attribute('sg', str(self.db_to_game_rank(other_profile.get_int(self.DAN_RANKING_SINGLE, -1), self.GAME_CLTYPE_SINGLE))) @@ -1880,7 +1880,7 @@ class IIDXSinobuz(IIDXCourse, IIDXBase): root.add_child(Node.void('bind_eaappli')) return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) play_stats = self.get_play_statistics(userid) diff --git a/bemani/backend/iidx/spada.py b/bemani/backend/iidx/spada.py index 5d24f1d..f67700b 100644 --- a/bemani/backend/iidx/spada.py +++ b/bemani/backend/iidx/spada.py @@ -7,7 +7,7 @@ from typing import Optional, Dict, List, Tuple, Any from bemani.backend.iidx.base import IIDXBase from bemani.backend.iidx.tricoro import IIDXTricoro -from bemani.common import ValidatedDict, VersionConstants, BroadcastConstants, Time, ID +from bemani.common import Profile, ValidatedDict, VersionConstants, BroadcastConstants, Time, ID from bemani.data import Data, UserID from bemani.protocol import Node @@ -360,7 +360,7 @@ class IIDXSpada(IIDXBase): ] totalscores: Dict[UserID, int] = {} - profiles: Dict[UserID, ValidatedDict] = {} + profiles: Dict[UserID, Profile] = {} for songid in songids: scores = self.data.local.music.get_all_scores( self.game, @@ -374,7 +374,7 @@ class IIDXSpada(IIDXBase): totalscores[score[0]] = 0 profile = self.get_any_profile(score[0]) if profile is None: - profile = ValidatedDict() + profile = Profile(self.game, self.version, "", 0) profiles[score[0]] = profile totalscores[score[0]] += score[1].points @@ -627,7 +627,7 @@ class IIDXSpada(IIDXBase): data = Node.void('data') ranklist.add_child(data) - data.set_attribute('iidx_id', str(profile.get_int('extid'))) + data.set_attribute('iidx_id', str(profile.extid)) data.set_attribute('name', profile.get_str('name')) machine_name = '' @@ -883,7 +883,7 @@ class IIDXSpada(IIDXBase): root = Node.void('IIDX21pc') root.set_attribute('name', profile.get_str('name')) - root.set_attribute('idstr', ID.format_extid(profile.get_int('extid'))) + root.set_attribute('idstr', ID.format_extid(profile.extid)) root.set_attribute('pid', str(profile.get_int('pid'))) return root @@ -895,7 +895,7 @@ class IIDXSpada(IIDXBase): root = Node.void('IIDX21pc') if newprofile is not None: - root.set_attribute('id', str(newprofile.get_int('extid'))) + root.set_attribute('id', str(newprofile.extid)) return root if method == 'reg': @@ -906,8 +906,8 @@ class IIDXSpada(IIDXBase): root = Node.void('IIDX21pc') if profile is not None: - root.set_attribute('id', str(profile.get_int('extid'))) - root.set_attribute('id_str', ID.format_extid(profile.get_int('extid'))) + root.set_attribute('id', str(profile.extid)) + root.set_attribute('id_str', ID.format_extid(profile.extid)) return root if method == 'get': @@ -942,7 +942,7 @@ class IIDXSpada(IIDXBase): if userid is not None: profile = self.get_profile(userid) if profile is None: - profile = ValidatedDict() + profile = Profile(self.game, self.version, "", extid) profile.replace_int('shop_location', location) self.put_profile(userid, profile) @@ -1081,7 +1081,7 @@ class IIDXSpada(IIDXBase): return Node.void('IIDX21pc') - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: root = Node.void('IIDX21pc') # Look up play stats we bridge to every mix @@ -1094,8 +1094,8 @@ class IIDXSpada(IIDXBase): # Profile data pcdata = Node.void('pcdata') root.add_child(pcdata) - pcdata.set_attribute('id', str(profile.get_int('extid'))) - pcdata.set_attribute('idstr', ID.format_extid(profile.get_int('extid'))) + pcdata.set_attribute('id', str(profile.extid)) + pcdata.set_attribute('idstr', ID.format_extid(profile.extid)) pcdata.set_attribute('name', profile.get_str('name')) pcdata.set_attribute('pid', str(profile.get_int('pid'))) pcdata.set_attribute('spnum', str(play_stats.get_int('single_plays'))) @@ -1287,8 +1287,8 @@ class IIDXSpada(IIDXBase): rival = Node.void('rival') rlist.add_child(rival) rival.set_attribute('spdp', rival_type) - rival.set_attribute('id', str(other_profile.get_int('extid'))) - rival.set_attribute('id_str', ID.format_extid(other_profile.get_int('extid'))) + rival.set_attribute('id', str(other_profile.extid)) + rival.set_attribute('id_str', ID.format_extid(other_profile.extid)) rival.set_attribute('djname', other_profile.get_str('name')) rival.set_attribute('pid', str(other_profile.get_int('pid'))) rival.set_attribute('sg', str(self.db_to_game_rank(other_profile.get_int(self.DAN_RANKING_SINGLE, -1), self.GAME_CLTYPE_SINGLE))) @@ -1464,7 +1464,7 @@ class IIDXSpada(IIDXBase): root.add_child(Node.void('bind_eaappli')) return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) play_stats = self.get_play_statistics(userid) diff --git a/bemani/backend/iidx/tricoro.py b/bemani/backend/iidx/tricoro.py index e014618..e60853b 100644 --- a/bemani/backend/iidx/tricoro.py +++ b/bemani/backend/iidx/tricoro.py @@ -6,7 +6,7 @@ from typing import Optional, Dict, List, Tuple, Any from bemani.backend.iidx.base import IIDXBase from bemani.backend.iidx.stubs import IIDXLincle -from bemani.common import ValidatedDict, VersionConstants, Time, ID +from bemani.common import Profile, ValidatedDict, VersionConstants, Time, ID from bemani.data import Data, UserID from bemani.protocol import Node @@ -359,7 +359,7 @@ class IIDXTricoro(IIDXBase): ] totalscores: Dict[UserID, int] = {} - profiles: Dict[UserID, ValidatedDict] = {} + profiles: Dict[UserID, Profile] = {} for songid in songids: scores = self.data.local.music.get_all_scores( self.game, @@ -373,7 +373,7 @@ class IIDXTricoro(IIDXBase): totalscores[score[0]] = 0 profile = self.get_any_profile(score[0]) if profile is None: - profile = ValidatedDict() + profile = Profile(self.game, self.version, "", 0) profiles[score[0]] = profile totalscores[score[0]] += score[1].points @@ -626,7 +626,7 @@ class IIDXTricoro(IIDXBase): data = Node.void('data') ranklist.add_child(data) - data.set_attribute('iidx_id', str(profile.get_int('extid'))) + data.set_attribute('iidx_id', str(profile.extid)) data.set_attribute('name', profile.get_str('name')) machine_name = '' @@ -870,7 +870,7 @@ class IIDXTricoro(IIDXBase): root = Node.void('pc') root.set_attribute('name', profile.get_str('name')) - root.set_attribute('idstr', ID.format_extid(profile.get_int('extid'))) + root.set_attribute('idstr', ID.format_extid(profile.extid)) root.set_attribute('pid', str(profile.get_int('pid'))) return root @@ -882,8 +882,8 @@ class IIDXTricoro(IIDXBase): root = Node.void('pc') if profile is not None: - root.set_attribute('id', str(profile.get_int('extid'))) - root.set_attribute('id_str', ID.format_extid(profile.get_int('extid'))) + root.set_attribute('id', str(profile.extid)) + root.set_attribute('id_str', ID.format_extid(profile.extid)) return root if method == 'get': @@ -918,7 +918,7 @@ class IIDXTricoro(IIDXBase): if userid is not None: profile = self.get_profile(userid) if profile is None: - profile = ValidatedDict() + profile = Profile(self.game, self.version, "", extid) profile.replace_int('shop_location', location) self.put_profile(userid, profile) @@ -977,7 +977,7 @@ class IIDXTricoro(IIDXBase): # Invalid method return None - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: root = Node.void('pc') # Look up play stats we bridge to every mix @@ -990,8 +990,8 @@ class IIDXTricoro(IIDXBase): # Profile data pcdata = Node.void('pcdata') root.add_child(pcdata) - pcdata.set_attribute('id', str(profile.get_int('extid'))) - pcdata.set_attribute('idstr', ID.format_extid(profile.get_int('extid'))) + pcdata.set_attribute('id', str(profile.extid)) + pcdata.set_attribute('idstr', ID.format_extid(profile.extid)) pcdata.set_attribute('name', profile.get_str('name')) pcdata.set_attribute('pid', str(profile.get_int('pid'))) pcdata.set_attribute('spnum', str(play_stats.get_int('single_plays'))) @@ -1105,8 +1105,8 @@ class IIDXTricoro(IIDXBase): rival = Node.void('rival') rlist.add_child(rival) rival.set_attribute('spdp', rival_type) - rival.set_attribute('id', str(other_profile.get_int('extid'))) - rival.set_attribute('id_str', ID.format_extid(other_profile.get_int('extid'))) + rival.set_attribute('id', str(other_profile.extid)) + rival.set_attribute('id_str', ID.format_extid(other_profile.extid)) rival.set_attribute('djname', other_profile.get_str('name')) rival.set_attribute('pid', str(other_profile.get_int('pid'))) rival.set_attribute('sg', str(self.db_to_game_rank(other_profile.get_int(self.DAN_RANKING_SINGLE, -1), self.GAME_CLTYPE_SINGLE))) @@ -1257,7 +1257,7 @@ class IIDXTricoro(IIDXBase): return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) play_stats = self.get_play_statistics(userid) diff --git a/bemani/backend/jubeat/base.py b/bemani/backend/jubeat/base.py index 74d3eca..49d96f3 100644 --- a/bemani/backend/jubeat/base.py +++ b/bemani/backend/jubeat/base.py @@ -3,7 +3,7 @@ from typing import Dict, List, Optional from bemani.backend.base import Base from bemani.backend.core import CoreHandler, CardManagerHandler, PASELIHandler -from bemani.common import DBConstants, GameConstants, ValidatedDict +from bemani.common import DBConstants, GameConstants, Profile, ValidatedDict from bemani.data import Score, UserID from bemani.protocol import Node @@ -43,7 +43,7 @@ class JubeatBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): """ return None - def put_profile(self, userid: UserID, profile: ValidatedDict) -> None: + def put_profile(self, userid: UserID, profile: Profile) -> None: """ Save a new profile for this user given a game/version. Overrides but calls the same functionality in Base, to ensure we don't save calculated values. @@ -56,21 +56,21 @@ class JubeatBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): del profile['has_old_version'] super().put_profile(userid, profile) - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> 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('gametop') - def format_scores(self, userid: UserID, profile: ValidatedDict, scores: List[Score]) -> Node: + def format_scores(self, userid: UserID, profile: Profile, scores: List[Score]) -> Node: """ Base handler for a score list. Given a userid, profile and a score list, return a Node representing a score list. Should be overridden. """ return Node.void('gametop') - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: """ Base handler for profile parsing. Given a request and an old profile, return a new profile that's been updated with the contents of the request. @@ -114,14 +114,18 @@ class JubeatBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): # First, create and save the default profile userid = self.data.remote.user.from_refid(self.game, self.version, refid) - defaultprofile = ValidatedDict({ - 'name': name, - }) - self.put_profile(userid, defaultprofile) + profile = Profile( + self.game, + self.version, + refid, + 0, + { + 'name': name, + }, + ) + self.put_profile(userid, profile) # Now, reload and format the profile, looking up the has old version flag - profile = self.get_profile(userid) - oldversion = self.previous_version() oldprofile = oldversion.get_profile(userid) profile['has_old_version'] = oldprofile is not None diff --git a/bemani/backend/jubeat/clan.py b/bemani/backend/jubeat/clan.py index 99c5bcb..6601fb6 100644 --- a/bemani/backend/jubeat/clan.py +++ b/bemani/backend/jubeat/clan.py @@ -15,7 +15,7 @@ from bemani.backend.jubeat.common import ( from bemani.backend.jubeat.qubell import JubeatQubell from bemani.backend.base import Status -from bemani.common import Time, ValidatedDict, VersionConstants +from bemani.common import Time, Profile, ValidatedDict, VersionConstants from bemani.data import Data, Achievement, Score, Song, UserID from bemani.protocol import Node @@ -1102,14 +1102,14 @@ class JubeatClan( return Node.void('gameend') - def format_scores(self, userid: UserID, profile: ValidatedDict, scores: List[Score]) -> Node: + def format_scores(self, userid: UserID, profile: Profile, scores: List[Score]) -> Node: root = Node.void('gametop') datanode = Node.void('data') root.add_child(datanode) player = Node.void('player') datanode.add_child(player) - player.add_child(Node.s32('jid', profile.get_int('extid'))) + player.add_child(Node.s32('jid', profile.extid)) playdata = Node.void('mdata_list') player.add_child(playdata) @@ -1185,7 +1185,7 @@ class JubeatClan( return root - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: root = Node.void('gametop') data = Node.void('data') root.add_child(data) @@ -1198,7 +1198,7 @@ class JubeatClan( # Basic profile info player.add_child(Node.string('name', profile.get_str('name', 'なし'))) - player.add_child(Node.s32('jid', profile.get_int('extid'))) + player.add_child(Node.s32('jid', profile.extid)) # Miscelaneous crap player.add_child(Node.s32('session_id', 1)) @@ -1288,7 +1288,7 @@ class JubeatClan( rival = Node.void('rival') rivallist.add_child(rival) - rival.add_child(Node.s32('jid', rprofile.get_int('extid'))) + rival.add_child(Node.s32('jid', rprofile.extid)) rival.add_child(Node.string('name', rprofile.get_str('name'))) # This looks like a carry-over from prop's career and isn't displayed. @@ -1577,7 +1577,7 @@ class JubeatClan( return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) data = request.child('data') diff --git a/bemani/backend/jubeat/prop.py b/bemani/backend/jubeat/prop.py index 9b869ed..799c431 100644 --- a/bemani/backend/jubeat/prop.py +++ b/bemani/backend/jubeat/prop.py @@ -16,7 +16,7 @@ from bemani.backend.jubeat.common import ( from bemani.backend.jubeat.course import JubeatCourse from bemani.backend.jubeat.base import JubeatBase from bemani.backend.jubeat.saucerfulfill import JubeatSaucerFulfill -from bemani.common import ValidatedDict, VersionConstants, Time +from bemani.common import Profile, ValidatedDict, VersionConstants, Time from bemani.data import Data, Score, UserID from bemani.protocol import Node @@ -205,7 +205,7 @@ class JubeatProp( return (promotions, neutrals, demotions) @classmethod - def _get_league_scores(cls, data: Data, current_id: int, profiles: List[Tuple[UserID, ValidatedDict]]) -> Tuple[List[Tuple[UserID, int]], List[UserID]]: + def _get_league_scores(cls, data: Data, current_id: int, profiles: List[Tuple[UserID, Profile]]) -> Tuple[List[Tuple[UserID, int]], List[UserID]]: """ Given the current League ID (calculated based on the date range) and a list of all user profiles for this game/version, return a uple containing two lists. @@ -681,7 +681,7 @@ class JubeatProp( userid = self.data.remote.user.from_extid(self.game, self.version, extid) profile = self.get_profile(userid) if profile is None: - profile = ValidatedDict() + profile = Profile(self.game, self.version, "", extid) # Player scores for courses player_list = Node.void('player_list') @@ -725,7 +725,7 @@ class JubeatProp( userid = self.data.remote.user.from_extid(self.game, self.version, extid) profile = self.get_profile(userid) if profile is None: - profile = ValidatedDict() + profile = Profile(self.game, self.version, "", extid) gametop = Node.void('gametop') data = Node.void('data') @@ -786,7 +786,7 @@ class JubeatProp( return gametop - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: root = Node.void('gametop') data = Node.void('data') root.add_child(data) @@ -798,7 +798,7 @@ class JubeatProp( # Basic profile info player.add_child(Node.string('name', profile.get_str('name', 'なし'))) - player.add_child(Node.s32('jid', profile.get_int('extid'))) + player.add_child(Node.s32('jid', profile.extid)) # Miscelaneous crap player.add_child(Node.s32('session_id', 1)) @@ -950,7 +950,7 @@ class JubeatProp( rival = Node.void('rival') rivallist.add_child(rival) - rival.add_child(Node.s32('jid', rprofile.get_int('extid'))) + rival.add_child(Node.s32('jid', rprofile.extid)) rival.add_child(Node.string('name', rprofile.get_str('name'))) rcareerdict = rprofile.get_dict('career') @@ -1082,7 +1082,7 @@ class JubeatProp( return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) data = request.child('data') @@ -1339,14 +1339,14 @@ class JubeatProp( return newprofile - def format_scores(self, userid: UserID, profile: ValidatedDict, scores: List[Score]) -> Node: + def format_scores(self, userid: UserID, profile: Profile, scores: List[Score]) -> Node: root = Node.void('gametop') datanode = Node.void('data') root.add_child(datanode) player = Node.void('player') datanode.add_child(player) - player.add_child(Node.s32('jid', profile.get_int('extid'))) + player.add_child(Node.s32('jid', profile.extid)) playdata = Node.void('mdata_list') player.add_child(playdata) diff --git a/bemani/backend/jubeat/qubell.py b/bemani/backend/jubeat/qubell.py index b4126c6..27a6a77 100644 --- a/bemani/backend/jubeat/qubell.py +++ b/bemani/backend/jubeat/qubell.py @@ -15,7 +15,7 @@ from bemani.backend.jubeat.common import ( ) from bemani.backend.jubeat.prop import JubeatProp -from bemani.common import ValidatedDict, VersionConstants +from bemani.common import Profile, ValidatedDict, VersionConstants from bemani.data import Data, Score, UserID from bemani.protocol import Node @@ -504,7 +504,7 @@ class JubeatQubell( return Node.void('gameend') - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: root = Node.void('gametop') data = Node.void('data') root.add_child(data) @@ -520,7 +520,7 @@ class JubeatQubell( # Basic profile info player.add_child(Node.string('name', profile.get_str('name', 'なし'))) - player.add_child(Node.s32('jid', profile.get_int('extid'))) + player.add_child(Node.s32('jid', profile.extid)) # Miscelaneous crap player.add_child(Node.s32('session_id', 1)) @@ -612,7 +612,7 @@ class JubeatQubell( rival = Node.void('rival') rivallist.add_child(rival) - rival.add_child(Node.s32('jid', rprofile.get_int('extid'))) + rival.add_child(Node.s32('jid', rprofile.extid)) rival.add_child(Node.string('name', rprofile.get_str('name'))) # This looks like a carry-over from prop's career and isn't displayed. @@ -841,14 +841,14 @@ class JubeatQubell( return root - def format_scores(self, userid: UserID, profile: ValidatedDict, scores: List[Score]) -> Node: + def format_scores(self, userid: UserID, profile: Profile, scores: List[Score]) -> Node: root = Node.void('gametop') datanode = Node.void('data') root.add_child(datanode) player = Node.void('player') datanode.add_child(player) - player.add_child(Node.s32('jid', profile.get_int('extid'))) + player.add_child(Node.s32('jid', profile.extid)) playdata = Node.void('mdata_list') player.add_child(playdata) @@ -919,7 +919,7 @@ class JubeatQubell( return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) data = request.child('data') diff --git a/bemani/backend/jubeat/saucer.py b/bemani/backend/jubeat/saucer.py index 0a16f3a..a0eb797 100644 --- a/bemani/backend/jubeat/saucer.py +++ b/bemani/backend/jubeat/saucer.py @@ -14,7 +14,7 @@ from bemani.backend.jubeat.common import ( JubeatLoggerReportHandler, ) from bemani.backend.jubeat.stubs import JubeatCopiousAppend -from bemani.common import ValidatedDict, VersionConstants, Time +from bemani.common import Profile, ValidatedDict, VersionConstants, Time from bemani.data import Data, Score, UserID from bemani.protocol import Node @@ -162,7 +162,7 @@ class JubeatSaucer( root.set_attribute('status', str(Status.NO_PROFILE)) return root - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: root = Node.void('gametop') data = Node.void('data') root.add_child(data) @@ -287,7 +287,7 @@ class JubeatSaucer( rival = Node.void('rival') rivallist.add_child(rival) - rival.add_child(Node.s32('jid', rprofile.get_int('extid'))) + rival.add_child(Node.s32('jid', rprofile.extid)) rival.add_child(Node.string('name', rprofile.get_str('name'))) # Lazy way of keeping track of rivals, since we can only have 4 @@ -450,8 +450,8 @@ class JubeatSaucer( # Basic profile info player.add_child(Node.string('name', profile.get_str('name', 'なし'))) - player.add_child(Node.s32('jid', profile.get_int('extid'))) - player.add_child(Node.string('refid', profile.get_str('refid'))) + player.add_child(Node.s32('jid', profile.extid)) + player.add_child(Node.string('refid', profile.refid)) # Miscelaneous history stuff data.add_child(Node.u8('termver', 16)) @@ -517,7 +517,7 @@ class JubeatSaucer( return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) data = request.child('data') @@ -657,14 +657,14 @@ class JubeatSaucer( return newprofile - def format_scores(self, userid: UserID, profile: ValidatedDict, scores: List[Score]) -> Node: + def format_scores(self, userid: UserID, profile: Profile, scores: List[Score]) -> Node: root = Node.void('gametop') datanode = Node.void('data') root.add_child(datanode) player = Node.void('player') datanode.add_child(player) - player.add_child(Node.s32('jid', profile.get_int('extid'))) + player.add_child(Node.s32('jid', profile.extid)) playdata = Node.void('playdata') player.add_child(playdata) playdata.set_attribute('count', str(len(scores))) diff --git a/bemani/backend/jubeat/saucerfulfill.py b/bemani/backend/jubeat/saucerfulfill.py index 466b102..3060aaa 100644 --- a/bemani/backend/jubeat/saucerfulfill.py +++ b/bemani/backend/jubeat/saucerfulfill.py @@ -15,7 +15,7 @@ from bemani.backend.jubeat.common import ( ) from bemani.backend.jubeat.course import JubeatCourse from bemani.backend.jubeat.saucer import JubeatSaucer -from bemani.common import ValidatedDict, VersionConstants, Time +from bemani.common import Profile, ValidatedDict, VersionConstants, Time from bemani.data import Data, Score, UserID from bemani.protocol import Node @@ -205,7 +205,7 @@ class JubeatSaucerFulfill( userid = self.data.remote.user.from_extid(self.game, self.version, extid) profile = self.get_profile(userid) if profile is None: - profile = ValidatedDict() + profile = Profile(self.game, self.version, "", extid) # Player scores for courses player_list = Node.void('player_list') @@ -293,7 +293,7 @@ class JubeatSaucerFulfill( root.set_attribute('status', str(Status.NO_PROFILE)) return root - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: root = Node.void('gametop') data = Node.void('data') root.add_child(data) @@ -471,7 +471,7 @@ class JubeatSaucerFulfill( rival = Node.void('rival') rivallist.add_child(rival) - rival.add_child(Node.s32('jid', rprofile.get_int('extid'))) + rival.add_child(Node.s32('jid', rprofile.extid)) rival.add_child(Node.string('name', rprofile.get_str('name'))) # Lazy way of keeping track of rivals, since we can only have 4 @@ -538,8 +538,8 @@ class JubeatSaucerFulfill( # Basic profile info player.add_child(Node.string('name', profile.get_str('name', 'なし'))) - player.add_child(Node.s32('jid', profile.get_int('extid'))) - player.add_child(Node.string('refid', profile.get_str('refid'))) + player.add_child(Node.s32('jid', profile.extid)) + player.add_child(Node.string('refid', profile.refid)) # Miscelaneous history stuff data.add_child(Node.u8('termver', 16)) @@ -598,7 +598,7 @@ class JubeatSaucerFulfill( return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) data = request.child('data') @@ -754,14 +754,14 @@ class JubeatSaucerFulfill( return newprofile - def format_scores(self, userid: UserID, profile: ValidatedDict, scores: List[Score]) -> Node: + def format_scores(self, userid: UserID, profile: Profile, scores: List[Score]) -> Node: root = Node.void('gametop') datanode = Node.void('data') root.add_child(datanode) player = Node.void('player') datanode.add_child(player) - player.add_child(Node.s32('jid', profile.get_int('extid'))) + player.add_child(Node.s32('jid', profile.extid)) playdata = Node.void('playdata') player.add_child(playdata) playdata.set_attribute('count', str(len(scores))) diff --git a/bemani/backend/museca/base.py b/bemani/backend/museca/base.py index a5190e4..e1c0daf 100644 --- a/bemani/backend/museca/base.py +++ b/bemani/backend/museca/base.py @@ -3,7 +3,7 @@ from typing import Dict, Optional, Any from bemani.backend.base import Base from bemani.backend.core import CoreHandler, CardManagerHandler, PASELIHandler -from bemani.common import ValidatedDict, GameConstants, DBConstants, Parallel, Model +from bemani.common import Profile, ValidatedDict, GameConstants, DBConstants, Parallel, Model from bemani.data import UserID, Data from bemani.protocol import Node @@ -100,24 +100,27 @@ class MusecaBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): # First, create and save the default profile userid = self.data.remote.user.from_refid(self.game, self.version, refid) - defaultprofile = ValidatedDict({ - 'name': name, - 'loc': locid, - }) - self.put_profile(userid, defaultprofile) - - # Now, reload and format the profile, looking up the has old version flag - profile = self.get_profile(userid) + profile = Profile( + self.game, + self.version, + refid, + 0, + { + 'name': name, + 'loc': locid, + }, + ) + self.put_profile(userid, profile) return self.format_profile(userid, profile) - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> 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') - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: """ Base handler for profile parsing. Given a request and an old profile, return a new profile that's been updated with the contents of the request. diff --git a/bemani/backend/museca/common.py b/bemani/backend/museca/common.py index 8adbed1..cc33ca5 100644 --- a/bemani/backend/museca/common.py +++ b/bemani/backend/museca/common.py @@ -56,7 +56,7 @@ class MusecaGameHiscoreHandler(MusecaBase): info.add_child(Node.u32('id', score.id)) info.add_child(Node.u32('type', score.chart)) info.add_child(Node.string('name', profile.get_str('name'))) - info.add_child(Node.string('seq', ID.format_extid(profile.get_int('extid')))) + info.add_child(Node.string('seq', ID.format_extid(profile.extid))) info.add_child(Node.u32('score', score.points)) # Add to global scores @@ -89,7 +89,7 @@ class MusecaGameHiscoreHandler(MusecaBase): info.add_child(Node.u32('id', score.id)) info.add_child(Node.u32('type', score.chart)) info.add_child(Node.string('name', profile.get_str('name'))) - info.add_child(Node.string('seq', ID.format_extid(profile.get_int('extid')))) + info.add_child(Node.string('seq', ID.format_extid(profile.extid))) info.add_child(Node.u32('score', score.points)) # Add to global scores diff --git a/bemani/backend/museca/museca1.py b/bemani/backend/museca/museca1.py index 541b1fa..a536101 100644 --- a/bemani/backend/museca/museca1.py +++ b/bemani/backend/museca/museca1.py @@ -12,7 +12,7 @@ from bemani.backend.museca.common import ( MusecaGameSaveMusicHandler, MusecaGameShopHandler, ) -from bemani.common import Time, VersionConstants, ValidatedDict, ID +from bemani.common import Time, VersionConstants, Profile, ID from bemani.data import UserID from bemani.protocol import Node @@ -200,12 +200,12 @@ class Museca1( return game - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: game = Node.void('game_3') # Generic profile stuff game.add_child(Node.string('name', profile.get_str('name'))) - game.add_child(Node.string('code', ID.format_extid(profile.get_int('extid')))) + game.add_child(Node.string('code', ID.format_extid(profile.extid))) game.add_child(Node.u32('gamecoin_packet', profile.get_int('packet'))) game.add_child(Node.u32('gamecoin_block', profile.get_int('block'))) game.add_child(Node.s16('skill_name_id', profile.get_int('skill_name_id', -1))) @@ -289,7 +289,7 @@ class Museca1( return game - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) # Update blaster energy and in-game currencies diff --git a/bemani/backend/museca/museca1plus.py b/bemani/backend/museca/museca1plus.py index 27f3d46..5173f9a 100644 --- a/bemani/backend/museca/museca1plus.py +++ b/bemani/backend/museca/museca1plus.py @@ -13,7 +13,7 @@ from bemani.backend.museca.common import ( MusecaGameShopHandler, ) from bemani.backend.museca.museca1 import Museca1 -from bemani.common import Time, VersionConstants, ValidatedDict, ID +from bemani.common import Time, VersionConstants, Profile, ID from bemani.data import UserID from bemani.protocol import Node @@ -334,12 +334,12 @@ class Museca1Plus( return game - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: game = Node.void('game_3') # Generic profile stuff game.add_child(Node.string('name', profile.get_str('name'))) - game.add_child(Node.string('code', ID.format_extid(profile.get_int('extid')))) + game.add_child(Node.string('code', ID.format_extid(profile.extid))) game.add_child(Node.u32('gamecoin_packet', profile.get_int('packet'))) game.add_child(Node.u32('gamecoin_block', profile.get_int('block'))) game.add_child(Node.s16('skill_name_id', profile.get_int('skill_name_id', -1))) @@ -428,7 +428,7 @@ class Museca1Plus( return game - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) # Update blaster energy and in-game currencies diff --git a/bemani/backend/popn/base.py b/bemani/backend/popn/base.py index 47939a8..4f1d2aa 100644 --- a/bemani/backend/popn/base.py +++ b/bemani/backend/popn/base.py @@ -3,7 +3,7 @@ from typing import Dict, Optional, Sequence from bemani.backend.base import Base from bemani.backend.core import CoreHandler, CardManagerHandler, PASELIHandler -from bemani.common import ValidatedDict, Time, GameConstants, DBConstants +from bemani.common import Profile, ValidatedDict, Time, GameConstants, DBConstants from bemani.data import UserID, Achievement, ScoreSaveException from bemani.protocol import Node @@ -48,14 +48,14 @@ class PopnMusicBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): """ return None - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> 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('playerdata') - def format_conversion(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_conversion(self, userid: UserID, profile: Profile) -> Node: """ Base handler for profile conversion. Given a userid and a profile dictionary, return a node which represents the converted profile for @@ -66,7 +66,7 @@ class PopnMusicBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): """ return Node.void('playerdata') - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: """ Base handler for profile parsing. Given a request and an old profile, return a new profile that's been updated with the contents of the request. @@ -137,12 +137,18 @@ class PopnMusicBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): userid = self.data.remote.user.from_refid(self.game, self.version, refid) if userid is None: raise Exception("Logic error! Didn't find user to tie profile to!") - defaultprofile = ValidatedDict({ - 'name': name, - }) + profile = Profile( + self.game, + self.version, + refid, + 0, + { + 'name': name, + }, + ) if chara is not None: - defaultprofile.replace_int('chara', chara) - self.put_profile(userid, defaultprofile) + profile.replace_int('chara', chara) + self.put_profile(userid, profile) for achievement in achievements: self.data.local.user.put_achievement( self.game, @@ -152,10 +158,6 @@ class PopnMusicBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): achievement.type, achievement.data, ) - - profile = self.get_profile(userid) - if profile is None: - raise Exception("Logic error! Didn't find profile after writing it!") return self.format_profile(userid, profile) def update_score( diff --git a/bemani/backend/popn/eclale.py b/bemani/backend/popn/eclale.py index 7f232c2..5cf0e6c 100644 --- a/bemani/backend/popn/eclale.py +++ b/bemani/backend/popn/eclale.py @@ -6,7 +6,7 @@ from typing import Dict, List, Optional from bemani.backend.popn.base import PopnMusicBase from bemani.backend.popn.lapistoria import PopnMusicLapistoria -from bemani.common import Time, ValidatedDict, VersionConstants +from bemani.common import Time, Profile, VersionConstants from bemani.data import UserID, Link from bemani.protocol import Node @@ -191,7 +191,7 @@ class PopnMusicEclale(PopnMusicBase): userid = None if userid is not None: - oldprofile = self.get_profile(userid) or ValidatedDict() + oldprofile = self.get_profile(userid) or Profile(self.game, self.version, refid, 0) newprofile = self.unformat_profile(userid, request, oldprofile) if newprofile is not None: @@ -236,7 +236,7 @@ class PopnMusicEclale(PopnMusicBase): if lumina >= price: # Update player lumina balance - profile = self.get_profile(userid) or ValidatedDict() + profile = self.get_profile(userid) or Profile(self.game, self.version, refid, 0) profile.replace_int('lumina', lumina - price) self.put_profile(userid, profile) @@ -323,7 +323,7 @@ class PopnMusicEclale(PopnMusicBase): # Grab the links that we care about. links = self.data.local.user.get_links(self.game, self.version, userid) - profiles: Dict[UserID, ValidatedDict] = {} + profiles: Dict[UserID, Profile] = {} rivals: List[Link] = [] for link in links: if link.type != 'rival': @@ -347,7 +347,7 @@ class PopnMusicEclale(PopnMusicBase): friend = Node.void('friend') root.add_child(friend) friend.add_child(Node.s16('no', no)) - friend.add_child(Node.string('g_pm_id', self.format_extid(rivalprofile.get_int('extid')))) # Eclale formats on its own + friend.add_child(Node.string('g_pm_id', self.format_extid(rivalprofile.extid))) # Eclale formats on its own friend.add_child(Node.string('name', rivalprofile.get_str('name', 'なし'))) friend.add_child(Node.s16('chara', rivalprofile.get_int('chara', -1))) # This might be for having non-active or non-confirmed friends, but setting to 0 makes the @@ -436,7 +436,7 @@ class PopnMusicEclale(PopnMusicBase): self.update_score(userid, songid, chart, points, medal, combo=combo, stats=stats) return root - def format_conversion(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_conversion(self, userid: UserID, profile: Profile) -> Node: root = Node.void('player23') root.add_child(Node.string('name', profile.get_str('name', 'なし'))) root.add_child(Node.s16('chara', profile.get_int('chara', -1))) @@ -488,7 +488,7 @@ class PopnMusicEclale(PopnMusicBase): crc = abs(binascii.crc32(data.encode('ascii'))) % 10000 return f'{data}{crc:04d}' - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: root = Node.void('player23') # Mark this as a current profile @@ -497,7 +497,7 @@ class PopnMusicEclale(PopnMusicBase): # Account stuff account = Node.void('account') root.add_child(account) - account.add_child(Node.string('g_pm_id', self.format_extid(profile.get_int('extid')))) # Eclale formats on its own + account.add_child(Node.string('g_pm_id', self.format_extid(profile.extid))) # Eclale formats on its own account.add_child(Node.string('name', profile.get_str('name', 'なし'))) account.add_child(Node.s8('tutorial', profile.get_int('tutorial'))) account.add_child(Node.s16('area_id', profile.get_int('area_id'))) @@ -695,7 +695,7 @@ class PopnMusicEclale(PopnMusicBase): return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) # Set that we've seen this profile diff --git a/bemani/backend/popn/fantasia.py b/bemani/backend/popn/fantasia.py index 33d5292..14ba57f 100644 --- a/bemani/backend/popn/fantasia.py +++ b/bemani/backend/popn/fantasia.py @@ -6,7 +6,7 @@ from bemani.backend.popn.base import PopnMusicBase from bemani.backend.popn.tunestreet import PopnMusicTuneStreet from bemani.backend.base import Status -from bemani.common import ValidatedDict, VersionConstants, Time, ID +from bemani.common import Profile, VersionConstants, Time, ID from bemani.data import Score, Link, UserID from bemani.protocol import Node @@ -68,14 +68,14 @@ class PopnMusicFantasia(PopnMusicBase): }[score.chart] return medal << (position * 4) - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> 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.string('g_pm_id', ID.format_extid(profile.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))) @@ -239,7 +239,7 @@ class PopnMusicFantasia(PopnMusicBase): return root - def format_conversion(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_conversion(self, userid: UserID, profile: Profile) -> Node: root = Node.void('playerdata') root.add_child(Node.string('name', profile.get_str('name', 'なし'))) @@ -271,7 +271,7 @@ class PopnMusicFantasia(PopnMusicBase): return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: # 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. @@ -422,7 +422,7 @@ class PopnMusicFantasia(PopnMusicBase): if userid is None: return root - oldprofile = self.get_profile(userid) or ValidatedDict() + oldprofile = self.get_profile(userid) or Profile(self.game, self.version, refid, 0) newprofile = self.unformat_profile(userid, request, oldprofile) if newprofile is not None: @@ -443,7 +443,7 @@ class PopnMusicFantasia(PopnMusicBase): # Grab the links that we care about. links = self.data.local.user.get_links(self.game, self.version, userid) - profiles: Dict[UserID, ValidatedDict] = {} + profiles: Dict[UserID, Profile] = {} rivals: List[Link] = [] for link in links: if link.type != 'rival': @@ -470,7 +470,7 @@ class PopnMusicFantasia(PopnMusicBase): # 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.string('g_pm_id', ID.format_extid(rivalprofile.extid))) friend.add_child(Node.s16('chara', rivalprofile.get_int('chara', -1))) # Perform hiscore/medal conversion. diff --git a/bemani/backend/popn/lapistoria.py b/bemani/backend/popn/lapistoria.py index 370ca9f..9d0389d 100644 --- a/bemani/backend/popn/lapistoria.py +++ b/bemani/backend/popn/lapistoria.py @@ -6,7 +6,7 @@ from bemani.backend.popn.base import PopnMusicBase from bemani.backend.popn.sunnypark import PopnMusicSunnyPark from bemani.backend.base import Status -from bemani.common import ValidatedDict, VersionConstants, Time, ID +from bemani.common import Profile, VersionConstants, Time, ID from bemani.data import UserID, Link from bemani.protocol import Node @@ -168,7 +168,7 @@ class PopnMusicLapistoria(PopnMusicBase): if userid is None: return root - oldprofile = self.get_profile(userid) or ValidatedDict() + oldprofile = self.get_profile(userid) or Profile(self.game, self.version, refid, 0) newprofile = self.unformat_profile(userid, request, oldprofile) if newprofile is not None: @@ -193,7 +193,7 @@ class PopnMusicLapistoria(PopnMusicBase): # Grab the links that we care about. links = self.data.local.user.get_links(self.game, self.version, userid) - profiles: Dict[UserID, ValidatedDict] = {} + profiles: Dict[UserID, Profile] = {} rivals: List[Link] = [] for link in links: if link.type != 'rival': @@ -217,7 +217,7 @@ class PopnMusicLapistoria(PopnMusicBase): friend = Node.void('friend') root.add_child(friend) friend.add_child(Node.s16('no', no)) - friend.add_child(Node.string('g_pm_id', ID.format_extid(rivalprofile.get_int('extid')))) + friend.add_child(Node.string('g_pm_id', ID.format_extid(rivalprofile.extid))) friend.add_child(Node.string('name', rivalprofile.get_str('name', 'なし'))) friend.add_child(Node.s16('chara', rivalprofile.get_int('chara', -1))) # This might be for having non-active or non-confirmed friends, but setting to 0 makes the @@ -319,7 +319,7 @@ class PopnMusicLapistoria(PopnMusicBase): # Invalid method return None - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: root = Node.void('player22') # Result @@ -329,7 +329,7 @@ class PopnMusicLapistoria(PopnMusicBase): account = Node.void('account') root.add_child(account) account.add_child(Node.string('name', profile.get_str('name', 'なし'))) - account.add_child(Node.string('g_pm_id', ID.format_extid(profile.get_int('extid')))) + account.add_child(Node.string('g_pm_id', ID.format_extid(profile.extid))) account.add_child(Node.s8('tutorial', profile.get_int('tutorial', -1))) account.add_child(Node.s16('read_news', profile.get_int('read_news', 0))) account.add_child(Node.s8('staff', 0)) @@ -548,7 +548,7 @@ class PopnMusicLapistoria(PopnMusicBase): return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) account = request.child('account') @@ -687,7 +687,7 @@ class PopnMusicLapistoria(PopnMusicBase): return newprofile - def format_conversion(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_conversion(self, userid: UserID, profile: Profile) -> Node: # Circular import, ugh from bemani.backend.popn.eclale import PopnMusicEclale diff --git a/bemani/backend/popn/sunnypark.py b/bemani/backend/popn/sunnypark.py index 80ef8f2..6701799 100644 --- a/bemani/backend/popn/sunnypark.py +++ b/bemani/backend/popn/sunnypark.py @@ -6,7 +6,7 @@ from bemani.backend.popn.base import PopnMusicBase from bemani.backend.popn.fantasia import PopnMusicFantasia from bemani.backend.base import Status -from bemani.common import ValidatedDict, VersionConstants, Time, ID +from bemani.common import Profile, VersionConstants, Time, ID from bemani.data import UserID, Link from bemani.protocol import Node @@ -46,14 +46,14 @@ class PopnMusicSunnyPark(PopnMusicBase): def previous_version(self) -> Optional[PopnMusicBase]: return PopnMusicFantasia(self.data, self.config, self.model) - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> 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.string('g_pm_id', ID.format_extid(profile.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))) @@ -292,7 +292,7 @@ class PopnMusicSunnyPark(PopnMusicBase): return root - def format_conversion(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_conversion(self, userid: UserID, profile: Profile) -> Node: # Circular import, ugh from bemani.backend.popn.lapistoria import PopnMusicLapistoria @@ -349,7 +349,7 @@ class PopnMusicSunnyPark(PopnMusicBase): return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) newprofile.replace_int('option', request.child_value('option')) newprofile.replace_int('chara', request.child_value('chara')) @@ -535,7 +535,7 @@ class PopnMusicSunnyPark(PopnMusicBase): if userid is None: return root - oldprofile = self.get_profile(userid) or ValidatedDict() + oldprofile = self.get_profile(userid) or Profile(self.game, self.version, refid, 0) newprofile = self.unformat_profile(userid, request, oldprofile) if newprofile is not None: @@ -556,7 +556,7 @@ class PopnMusicSunnyPark(PopnMusicBase): # Grab the links that we care about. links = self.data.local.user.get_links(self.game, self.version, userid) - profiles: Dict[UserID, ValidatedDict] = {} + profiles: Dict[UserID, Profile] = {} rivals: List[Link] = [] for link in links: if link.type != 'rival': @@ -583,7 +583,7 @@ class PopnMusicSunnyPark(PopnMusicBase): # 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.string('g_pm_id', ID.format_extid(rivalprofile.extid))) friend.add_child(Node.s16('chara', rivalprofile.get_int('chara', -1))) # Set up player avatar. @@ -611,7 +611,7 @@ class PopnMusicSunnyPark(PopnMusicBase): ]: continue - points = score.points + rivalprofile.get_int('extid') % 100 + points = score.points medal = { self.PLAY_MEDAL_CIRCLE_FAILED: self.GAME_PLAY_MEDAL_CIRCLE_FAILED, self.PLAY_MEDAL_DIAMOND_FAILED: self.GAME_PLAY_MEDAL_DIAMOND_FAILED, diff --git a/bemani/backend/popn/tunestreet.py b/bemani/backend/popn/tunestreet.py index 6a13f01..037e4ee 100644 --- a/bemani/backend/popn/tunestreet.py +++ b/bemani/backend/popn/tunestreet.py @@ -6,7 +6,7 @@ from bemani.backend.popn.base import PopnMusicBase from bemani.backend.popn.stubs import PopnMusicSengokuRetsuden from bemani.backend.base import Status -from bemani.common import ValidatedDict, VersionConstants +from bemani.common import Profile, VersionConstants from bemani.data import Score, UserID from bemani.protocol import Node @@ -100,7 +100,7 @@ class PopnMusicTuneStreet(PopnMusicBase): }[score.data.get_int('medal')] return (flags << shift) | playedflag - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: root = Node.void('playerdata') # Format profile @@ -202,7 +202,7 @@ class PopnMusicTuneStreet(PopnMusicBase): return root - def format_conversion(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_conversion(self, userid: UserID, profile: Profile) -> Node: root = Node.void('playerdata') root.add_child(Node.string('name', profile.get_str('name', 'なし'))) @@ -230,7 +230,7 @@ class PopnMusicTuneStreet(PopnMusicBase): return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) # Extract the playmode, important for scores later @@ -392,7 +392,7 @@ class PopnMusicTuneStreet(PopnMusicBase): if userid is None: return root - oldprofile = self.get_profile(userid) or ValidatedDict() + oldprofile = self.get_profile(userid) or Profile(self.game, self.version, refid, 0) newprofile = self.unformat_profile(userid, request, oldprofile) if newprofile is not None: diff --git a/bemani/backend/popn/usaneko.py b/bemani/backend/popn/usaneko.py index 2f828ba..7f2495d 100644 --- a/bemani/backend/popn/usaneko.py +++ b/bemani/backend/popn/usaneko.py @@ -6,7 +6,7 @@ from typing import Any, Dict, List, Optional, Tuple from bemani.backend.popn.base import PopnMusicBase from bemani.backend.popn.eclale import PopnMusicEclale -from bemani.common import Time, ID, ValidatedDict, VersionConstants, Parallel +from bemani.common import Time, ID, Profile, ValidatedDict, VersionConstants, Parallel from bemani.data import Data, UserID, Achievement, Link from bemani.protocol import Node @@ -205,7 +205,7 @@ class PopnMusicUsaNeko(PopnMusicBase): ) # Cache of userID to profile - userid_to_profile: Dict[UserID, ValidatedDict] = {uid: profile for (uid, profile) in profiles} + userid_to_profile: Dict[UserID, Profile] = {uid: profile for (uid, profile) in profiles} # Course ranking info for the last 256 courses for course_info in course_infos[:256]: @@ -224,7 +224,7 @@ class PopnMusicUsaNeko(PopnMusicBase): chart_rankings = course_rankings.get(name, []) for pos, (uid, ach) in enumerate(chart_rankings[:20]): - profile = userid_to_profile.get(uid, ValidatedDict()) + profile = userid_to_profile.get(uid, Profile(self.game, self.version, "", 0)) subnode = Node.void(name) ranking_info.add_child(subnode) @@ -395,7 +395,7 @@ class PopnMusicUsaNeko(PopnMusicBase): userid = None if userid is not None: - oldprofile = self.get_profile(userid) or ValidatedDict() + oldprofile = self.get_profile(userid) or Profile(self.game, self.version, refid, 0) newprofile = self.unformat_profile(userid, request, oldprofile) if newprofile is not None: @@ -453,7 +453,7 @@ class PopnMusicUsaNeko(PopnMusicBase): # Handle fetching all scores uids_and_courses, profile = Parallel.execute([ lambda: self.data.local.user.get_all_achievements(self.game, self.version), - lambda: self.get_profile(userid) or ValidatedDict() + lambda: self.get_profile(userid) or Profile(self.game, self.version, "", 0) ]) # Grab a sorted list of all scores for this course and chart @@ -513,7 +513,7 @@ class PopnMusicUsaNeko(PopnMusicBase): # Grab the links that we care about. links = self.data.local.user.get_links(self.game, self.version, userid) - profiles: Dict[UserID, ValidatedDict] = {} + profiles: Dict[UserID, Profile] = {} rivals: List[Link] = [] for link in links: if link.type != 'rival': @@ -537,7 +537,7 @@ class PopnMusicUsaNeko(PopnMusicBase): friend = Node.void('friend') root.add_child(friend) friend.add_child(Node.s16('no', no)) - friend.add_child(Node.string('g_pm_id', self.format_extid(rivalprofile.get_int('extid')))) # UsaNeko formats on its own + friend.add_child(Node.string('g_pm_id', self.format_extid(rivalprofile.extid))) # UsaNeko formats on its own friend.add_child(Node.string('name', rivalprofile.get_str('name', 'なし'))) friend.add_child(Node.s16('chara', rivalprofile.get_int('chara', -1))) # This might be for having non-active or non-confirmed friends, but setting to 0 makes the @@ -714,7 +714,7 @@ class PopnMusicUsaNeko(PopnMusicBase): if lumina >= price: # Update player lumina balance - profile = self.get_profile(userid) or ValidatedDict() + profile = self.get_profile(userid) or Profile(self.game, self.version, refid, 0) profile.replace_int('player_point', lumina - price) self.put_profile(userid, profile) @@ -733,7 +733,7 @@ class PopnMusicUsaNeko(PopnMusicBase): return Node.void('player24') - def format_conversion(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_conversion(self, userid: UserID, profile: Profile) -> Node: root = Node.void('player24') root.add_child(Node.string('name', profile.get_str('name', 'なし'))) root.add_child(Node.s16('chara', profile.get_int('chara', -1))) @@ -785,7 +785,7 @@ class PopnMusicUsaNeko(PopnMusicBase): crc = abs(binascii.crc32(data.encode('ascii'))) % 10000 return f'{data}{crc:04d}' - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: root = Node.void('player24') # Mark this as a current profile @@ -794,7 +794,7 @@ class PopnMusicUsaNeko(PopnMusicBase): # Basic account info account = Node.void('account') root.add_child(account) - account.add_child(Node.string('g_pm_id', self.format_extid(profile.get_int('extid')))) + account.add_child(Node.string('g_pm_id', self.format_extid(profile.extid))) account.add_child(Node.string('name', profile.get_str('name', 'なし'))) account.add_child(Node.s16('tutorial', profile.get_int('tutorial'))) account.add_child(Node.s16('area_id', profile.get_int('area_id'))) @@ -1124,7 +1124,7 @@ class PopnMusicUsaNeko(PopnMusicBase): return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) # Set that we've seen this profile diff --git a/bemani/backend/reflec/base.py b/bemani/backend/reflec/base.py index f67e1fd..5a783b9 100644 --- a/bemani/backend/reflec/base.py +++ b/bemani/backend/reflec/base.py @@ -3,7 +3,7 @@ from typing import Dict, List, Optional from bemani.backend.base import Base from bemani.backend.core import CoreHandler, CardManagerHandler, PASELIHandler -from bemani.common import ValidatedDict, GameConstants, DBConstants, Time +from bemani.common import Profile, ValidatedDict, GameConstants, DBConstants, Time from bemani.data import Machine, ScoreSaveException, UserID from bemani.protocol import Node @@ -51,14 +51,14 @@ class ReflecBeatBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): 'lobby2', ] - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> 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('pc') - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: """ Base handler for profile parsing. Given a request and an old profile, return a new profile that's been updated with the contents of the request. @@ -86,7 +86,7 @@ class ReflecBeatBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): return None return self.format_profile(userid, profile) - def put_profile_by_refid(self, refid: Optional[str], request: Node) -> Optional[ValidatedDict]: + def put_profile_by_refid(self, refid: Optional[str], request: Node) -> Optional[Profile]: """ Given a RefID and a request node, unformat the profile and save it. """ @@ -97,8 +97,8 @@ class ReflecBeatBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): oldprofile = self.get_profile(userid) if oldprofile is None: # Create one so we can get refid/extid - self.put_profile(userid, ValidatedDict()) - oldprofile = self.get_profile(userid) + oldprofile = Profile(self.game, self.version, refid, 0) + self.put_profile(userid, oldprofile) newprofile = self.unformat_profile(userid, request, oldprofile) if newprofile is not None: self.put_profile(userid, newprofile) diff --git a/bemani/backend/reflec/colette.py b/bemani/backend/reflec/colette.py index 00b49c0..df065e1 100644 --- a/bemani/backend/reflec/colette.py +++ b/bemani/backend/reflec/colette.py @@ -4,7 +4,7 @@ from typing import Optional, Dict, List, Tuple, Any from bemani.backend.reflec.base import ReflecBeatBase from bemani.backend.reflec.limelight import ReflecBeatLimelight -from bemani.common import ValidatedDict, VersionConstants, ID, Time +from bemani.common import Profile, ValidatedDict, VersionConstants, ID, Time from bemani.data import UserID, Achievement from bemani.protocol import Node @@ -234,13 +234,19 @@ class ReflecBeatColette(ReflecBeatBase): } # Handle anonymous comments by returning a default profile - uid_mapping[UserID(0)] = ValidatedDict({'name': 'PLAYER', 'extid': 0}) + uid_mapping[UserID(0)] = Profile( + self.game, + self.version, + "", + 0, + {'name': 'PLAYER'}, + ) def add_comments(name: str, selected: List[Tuple[UserID, Achievement]]) -> None: for (uid, ach) in selected: cmnt = Node.void(name) root.add_child(cmnt) - cmnt.add_child(Node.s32('uid', uid_mapping[uid].get_int('extid'))) + cmnt.add_child(Node.s32('uid', uid_mapping[uid].extid)) cmnt.add_child(Node.string('name', uid_mapping[uid].get_str('name'))) cmnt.add_child(Node.s16('icon', ach.data.get_int('icon'))) cmnt.add_child(Node.s8('bln', ach.data.get_int('bln'))) @@ -387,7 +393,7 @@ class ReflecBeatColette(ReflecBeatBase): 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.s32('uid', profile.extid)) e.add_child(Node.s32('uattr', profile.get_int('uattr'))) e.add_child(Node.string('pn', profile.get_str('name'))) e.add_child(Node.s16('mg', profile.get_int('mg'))) @@ -442,7 +448,7 @@ class ReflecBeatColette(ReflecBeatBase): 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.s32('uid', profile.extid)) e.add_child(Node.s32('uattr', profile.get_int('uattr'))) e.add_child(Node.string('pn', profile.get_str('name'))) e.add_child(Node.s16('mg', profile.get_int('mg'))) @@ -686,10 +692,10 @@ class ReflecBeatColette(ReflecBeatBase): if profile is None: root.add_child(Node.s32('uid', 0)) else: - root.add_child(Node.s32('uid', profile.get_int('extid'))) + root.add_child(Node.s32('uid', profile.extid)) return root - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> 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) @@ -713,7 +719,7 @@ class ReflecBeatColette(ReflecBeatBase): account = Node.void('account') pdata.add_child(account) - account.add_child(Node.s32('usrid', profile.get_int('extid'))) + account.add_child(Node.s32('usrid', profile.extid)) account.add_child(Node.s32('tpc', statistics.get_int('total_plays', 0))) account.add_child(Node.s32('dpc', today_count)) account.add_child(Node.s32('crd', 1)) @@ -755,7 +761,7 @@ class ReflecBeatColette(ReflecBeatBase): r = Node.void('r') rival.add_child(r) r.add_child(Node.s32('slot_id', slotid)) - r.add_child(Node.s32('id', rprofile.get_int('extid'))) + r.add_child(Node.s32('id', rprofile.extid)) r.add_child(Node.string('name', rprofile.get_str('name'))) r.add_child(Node.bool('friend', True)) r.add_child(Node.bool('locked', False)) @@ -945,7 +951,7 @@ class ReflecBeatColette(ReflecBeatBase): return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: game_config = self.get_game_config() newprofile = copy.deepcopy(oldprofile) diff --git a/bemani/backend/reflec/groovin.py b/bemani/backend/reflec/groovin.py index ed1f309..a98dad6 100644 --- a/bemani/backend/reflec/groovin.py +++ b/bemani/backend/reflec/groovin.py @@ -4,7 +4,7 @@ from typing import Optional, Dict, Any, List, Tuple from bemani.backend.reflec.base import ReflecBeatBase from bemani.backend.reflec.colette import ReflecBeatColette -from bemani.common import ValidatedDict, VersionConstants, ID, Time +from bemani.common import Profile, ValidatedDict, VersionConstants, ID, Time from bemani.data import Achievement, Attempt, Score, UserID from bemani.protocol import Node @@ -168,7 +168,7 @@ class ReflecBeatGroovin(ReflecBeatBase): 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.s32('uid', profile.extid)) e.add_child(Node.s32('uattr', profile.get_int('uattr'))) e.add_child(Node.string('pn', profile.get_str('name'))) e.add_child(Node.s32('plyid', info.get_int('id'))) @@ -223,7 +223,7 @@ class ReflecBeatGroovin(ReflecBeatBase): 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.s32('uid', profile.extid)) e.add_child(Node.s32('uattr', profile.get_int('uattr'))) e.add_child(Node.string('pn', profile.get_str('name'))) e.add_child(Node.s32('plyid', info.get_int('id'))) @@ -349,7 +349,7 @@ class ReflecBeatGroovin(ReflecBeatBase): data = Node.void('data') rootnode.add_child(data) data.add_child(Node.s16('day_id', int((Time.now() - timeoffset) / Time.SECONDS_IN_DAY))) - data.add_child(Node.s32('user_id', profile.get_int('extid'))) + data.add_child(Node.s32('user_id', profile.extid)) data.add_child(Node.s16('icon_id', profile.get_dict('config').get_int('icon_id'))) data.add_child(Node.s16('point', min(points_by_user.get(userid, 0), 32767))) data.add_child(Node.s32('update_time', Time.now())) @@ -421,7 +421,7 @@ class ReflecBeatGroovin(ReflecBeatBase): root.add_child(shop_score) shop_score.add_child(Node.s32('time', Time.now())) - profiles: Dict[UserID, ValidatedDict] = {} + profiles: Dict[UserID, Profile] = {} for songid in range(start_music_id, end_music_id + 1): allscores = self.data.local.music.get_all_scores( self.game, @@ -453,7 +453,7 @@ class ReflecBeatGroovin(ReflecBeatBase): data.add_child(Node.s16('music_id', songid)) data.add_child(Node.s8('note_grade', score.chart)) data.add_child(Node.s8('clear_type', self.__db_to_game_clear_type(score.data.get_int('clear_type')))) - data.add_child(Node.s32('user_id', profile.get_int('extid'))) + data.add_child(Node.s32('user_id', profile.extid)) data.add_child(Node.s16('icon_id', profile.get_dict('config').get_int('icon_id'))) data.add_child(Node.s32('score', score.points)) data.add_child(Node.s32('time', score.timestamp)) @@ -499,13 +499,19 @@ class ReflecBeatGroovin(ReflecBeatBase): } # Handle anonymous comments by returning a default profile - uid_mapping[UserID(0)] = ValidatedDict({'name': 'PLAYER', 'extid': 0}) + uid_mapping[UserID(0)] = Profile( + self.game, + self.version, + "", + 0, + {'name': 'PLAYER'}, + ) def add_comments(name: str, selected: List[Tuple[UserID, Achievement]]) -> None: for (uid, ach) in selected: cmnt = Node.void(name) root.add_child(cmnt) - cmnt.add_child(Node.s32('uid', uid_mapping[uid].get_int('extid'))) + cmnt.add_child(Node.s32('uid', uid_mapping[uid].extid)) cmnt.add_child(Node.string('name', uid_mapping[uid].get_str('name'))) cmnt.add_child(Node.s16('icon', ach.data.get_int('icon'))) cmnt.add_child(Node.s8('bln', ach.data.get_int('bln'))) @@ -909,10 +915,10 @@ class ReflecBeatGroovin(ReflecBeatBase): if profile is None: root.add_child(Node.s32('uid', 0)) else: - root.add_child(Node.s32('uid', profile.get_int('extid'))) + root.add_child(Node.s32('uid', profile.extid)) return root - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> 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) @@ -936,7 +942,7 @@ class ReflecBeatGroovin(ReflecBeatBase): # Account info account = Node.void('account') pdata.add_child(account) - account.add_child(Node.s32('usrid', profile.get_int('extid'))) + account.add_child(Node.s32('usrid', profile.extid)) account.add_child(Node.s32('tpc', statistics.get_int('total_plays', 0))) account.add_child(Node.s32('dpc', today_count)) account.add_child(Node.s32('crd', 1)) @@ -995,7 +1001,7 @@ class ReflecBeatGroovin(ReflecBeatBase): r = Node.void('r') rival.add_child(r) r.add_child(Node.s32('slot_id', slotid)) - r.add_child(Node.s32('id', rprofile.get_int('extid'))) + r.add_child(Node.s32('id', rprofile.extid)) r.add_child(Node.string('name', rprofile.get_str('name'))) r.add_child(Node.s32('icon', profile.get_dict('config').get_int('icon_id'))) r.add_child(Node.s32('m_level', profile.get_int('mg'))) @@ -1211,7 +1217,7 @@ class ReflecBeatGroovin(ReflecBeatBase): return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: game_config = self.get_game_config() newprofile = copy.deepcopy(oldprofile) @@ -1375,8 +1381,8 @@ class ReflecBeatGroovin(ReflecBeatBase): # 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")}') + if extid != newprofile.extid: + raise Exception(f'Unexpected user ID, got {extid} expecting {newprofile.extid}') episode_type = child.child_value('type') episode_value0 = child.child_value('value0') diff --git a/bemani/backend/reflec/limelight.py b/bemani/backend/reflec/limelight.py index eb63cbb..26ba638 100644 --- a/bemani/backend/reflec/limelight.py +++ b/bemani/backend/reflec/limelight.py @@ -4,7 +4,7 @@ from typing import Optional, Dict, Any, Tuple from bemani.backend.reflec.base import ReflecBeatBase from bemani.backend.reflec.reflecbeat import ReflecBeat -from bemani.common import ValidatedDict, VersionConstants, ID, Time +from bemani.common import Profile, VersionConstants, ID, Time from bemani.data import UserID from bemani.protocol import Node @@ -215,7 +215,7 @@ class ReflecBeatLimelight(ReflecBeatBase): c = Node.void('c') commentnode.add_child(c) - c.add_child(Node.s32('uid', uid_mapping[uid].get_int('extid'))) + c.add_child(Node.s32('uid', uid_mapping[uid].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'))) @@ -241,7 +241,7 @@ class ReflecBeatLimelight(ReflecBeatBase): s = Node.void('s') statusnode.add_child(s) - s.add_child(Node.s32('uid', uid_mapping[uid].get_int('extid'))) + s.add_child(Node.s32('uid', uid_mapping[uid].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'))) @@ -365,7 +365,7 @@ class ReflecBeatLimelight(ReflecBeatBase): 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.s32('uid', profile.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'))) @@ -415,7 +415,7 @@ class ReflecBeatLimelight(ReflecBeatBase): 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.s32('uid', profile.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'))) @@ -537,11 +537,11 @@ class ReflecBeatLimelight(ReflecBeatBase): if profile is None: root.add_child(Node.s32('uid', 0)) else: - root.add_child(Node.s32('uid', profile.get_int('extid'))) + root.add_child(Node.s32('uid', profile.extid)) root.add_child(Node.s32('time', Time.now())) return root - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> 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) @@ -553,7 +553,7 @@ class ReflecBeatLimelight(ReflecBeatBase): base = Node.void('base') pdata.add_child(base) - base.add_child(Node.s32('uid', profile.get_int('extid'))) + base.add_child(Node.s32('uid', profile.extid)) base.add_child(Node.string('name', profile.get_str('name'))) base.add_child(Node.s16('icon_id', profile.get_int('icon'))) base.add_child(Node.s16('lv', profile.get_int('lvl'))) @@ -709,7 +709,7 @@ class ReflecBeatLimelight(ReflecBeatBase): rival.add_child(r) r.add_child(Node.u8('slot_id', slotid)) r.add_child(Node.string('name', rprofile.get_str('name'))) - r.add_child(Node.s32('id', rprofile.get_int('extid'))) + r.add_child(Node.s32('id', rprofile.extid)) r.add_child(Node.bool('friend', True)) r.add_child(Node.bool('locked', False)) r.add_child(Node.s32('rc', 0)) @@ -747,7 +747,7 @@ class ReflecBeatLimelight(ReflecBeatBase): return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: game_config = self.get_game_config() newprofile = copy.deepcopy(oldprofile) diff --git a/bemani/backend/reflec/reflecbeat.py b/bemani/backend/reflec/reflecbeat.py index 0462765..4890ff3 100644 --- a/bemani/backend/reflec/reflecbeat.py +++ b/bemani/backend/reflec/reflecbeat.py @@ -3,7 +3,7 @@ from typing import Any, Dict, Tuple from bemani.backend.reflec.base import ReflecBeatBase -from bemani.common import ValidatedDict, VersionConstants, ID, Time +from bemani.common import Profile, VersionConstants, ID, Time from bemani.data import UserID from bemani.protocol import Node @@ -178,7 +178,7 @@ class ReflecBeat(ReflecBeatBase): 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.s32('uid', profile.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'))) @@ -221,7 +221,7 @@ class ReflecBeat(ReflecBeatBase): 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.s32('uid', profile.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'))) @@ -298,11 +298,11 @@ class ReflecBeat(ReflecBeatBase): if profile is None: root.add_child(Node.s32('uid', 0)) else: - root.add_child(Node.s32('uid', profile.get_int('extid'))) + root.add_child(Node.s32('uid', profile.extid)) root.add_child(Node.s32('time', Time.now())) return root - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> 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) @@ -313,7 +313,7 @@ class ReflecBeat(ReflecBeatBase): base = Node.void('base') pdata.add_child(base) - base.add_child(Node.s32('uid', profile.get_int('extid'))) + base.add_child(Node.s32('uid', profile.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'))) @@ -408,7 +408,7 @@ class ReflecBeat(ReflecBeatBase): return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: game_config = self.get_game_config() newprofile = copy.deepcopy(oldprofile) diff --git a/bemani/backend/reflec/volzza.py b/bemani/backend/reflec/volzza.py index 4ae8cc8..c32bccb 100644 --- a/bemani/backend/reflec/volzza.py +++ b/bemani/backend/reflec/volzza.py @@ -5,7 +5,7 @@ from bemani.backend.reflec.base import ReflecBeatBase from bemani.backend.reflec.volzzabase import ReflecBeatVolzzaBase from bemani.backend.reflec.groovin import ReflecBeatGroovin -from bemani.common import ValidatedDict, VersionConstants, ID, Time +from bemani.common import Profile, ValidatedDict, VersionConstants, ID, Time from bemani.data import Score, UserID from bemani.protocol import Node @@ -139,7 +139,7 @@ class ReflecBeatVolzza(ReflecBeatVolzzaBase): rl = Node.void('rl') rival_data.add_child(rl) - rl.add_child(Node.s32('uid', rprofile.get_int('extid'))) + rl.add_child(Node.s32('uid', rprofile.extid)) rl.add_child(Node.string('nm', rprofile.get_str('name'))) rl.add_child(Node.s16('ic', rprofile.get_dict('config').get_int('icon_id'))) @@ -236,7 +236,7 @@ class ReflecBeatVolzza(ReflecBeatVolzzaBase): ) minigame_scores = sorted( [ - all_profiles.get(userid, ValidatedDict()).get_int('mgsc') + all_profiles.get(userid, Profile(self.game, self.version, "", 0)).get_int('mgsc') for userid in all_users ], reverse=True, @@ -298,10 +298,10 @@ class ReflecBeatVolzza(ReflecBeatVolzzaBase): if profile is None: root.add_child(Node.s32('uid', 0)) else: - root.add_child(Node.s32('uid', profile.get_int('extid'))) + root.add_child(Node.s32('uid', profile.extid)) return root - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> 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) @@ -332,7 +332,7 @@ class ReflecBeatVolzza(ReflecBeatVolzzaBase): # Account info account = Node.void('account') pdata.add_child(account) - account.add_child(Node.s32('usrid', profile.get_int('extid'))) + account.add_child(Node.s32('usrid', profile.extid)) account.add_child(Node.s32('tpc', statistics.get_int('total_plays', 0))) account.add_child(Node.s32('dpc', today_count)) account.add_child(Node.s32('crd', 1)) @@ -380,7 +380,7 @@ class ReflecBeatVolzza(ReflecBeatVolzzaBase): r = Node.void('r') rival.add_child(r) r.add_child(Node.s32('slot_id', slotid)) - r.add_child(Node.s32('id', rprofile.get_int('extid'))) + r.add_child(Node.s32('id', rprofile.extid)) r.add_child(Node.string('name', rprofile.get_str('name'))) r.add_child(Node.s32('icon', rprofile.get_dict('config').get_int('icon_id'))) r.add_child(Node.s32('class', rprofile.get_int('class'))) @@ -554,7 +554,7 @@ class ReflecBeatVolzza(ReflecBeatVolzzaBase): return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: game_config = self.get_game_config() newprofile = copy.deepcopy(oldprofile) @@ -652,8 +652,8 @@ class ReflecBeatVolzza(ReflecBeatVolzzaBase): # 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")}') + if extid != newprofile.extid: + raise Exception(f'Unexpected user ID, got {extid} expecting {newprofile.extid}') episode_type = child.child_value('type') episode_value0 = child.child_value('value0') diff --git a/bemani/backend/reflec/volzza2.py b/bemani/backend/reflec/volzza2.py index e0992f9..633fc35 100644 --- a/bemani/backend/reflec/volzza2.py +++ b/bemani/backend/reflec/volzza2.py @@ -5,7 +5,7 @@ from bemani.backend.reflec.base import ReflecBeatBase from bemani.backend.reflec.volzzabase import ReflecBeatVolzzaBase from bemani.backend.reflec.volzza import ReflecBeatVolzza -from bemani.common import ValidatedDict, VersionConstants, ID, Time +from bemani.common import Profile, ValidatedDict, VersionConstants, ID, Time from bemani.data import Score, UserID from bemani.protocol import Node @@ -158,7 +158,7 @@ class ReflecBeatVolzza2(ReflecBeatVolzzaBase): rl = Node.void('rl') rival_data.add_child(rl) - rl.add_child(Node.s32('uid', rprofile.get_int('extid'))) + rl.add_child(Node.s32('uid', rprofile.extid)) rl.add_child(Node.string('nm', rprofile.get_str('name'))) rl.add_child(Node.s16('ic', rprofile.get_dict('config').get_int('icon_id'))) @@ -255,7 +255,7 @@ class ReflecBeatVolzza2(ReflecBeatVolzzaBase): ) minigame_scores = sorted( [ - all_profiles.get(userid, ValidatedDict()).get_int('mgsc') + all_profiles.get(userid, Profile(self.game, self.version, "", 0)).get_int('mgsc') for userid in all_users ], reverse=True, @@ -317,15 +317,15 @@ class ReflecBeatVolzza2(ReflecBeatVolzzaBase): if profile is None: root.add_child(Node.s32('uid', 0)) else: - root.add_child(Node.s32('uid', profile.get_int('extid'))) + root.add_child(Node.s32('uid', profile.extid)) return root - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> 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) links = self.data.local.user.get_links(self.game, self.version, userid) - rprofiles: Dict[UserID, ValidatedDict] = {} + rprofiles: Dict[UserID, Profile] = {} root = Node.void('player') pdata = Node.void('pdata') root.add_child(pdata) @@ -352,7 +352,7 @@ class ReflecBeatVolzza2(ReflecBeatVolzzaBase): # Account info account = Node.void('account') pdata.add_child(account) - account.add_child(Node.s32('usrid', profile.get_int('extid'))) + account.add_child(Node.s32('usrid', profile.extid)) account.add_child(Node.s32('tpc', statistics.get_int('total_plays', 0))) account.add_child(Node.s32('dpc', today_count)) account.add_child(Node.s32('crd', 1)) @@ -407,7 +407,7 @@ class ReflecBeatVolzza2(ReflecBeatVolzzaBase): r = Node.void('r') rival.add_child(r) r.add_child(Node.s32('slot_id', slotid)) - r.add_child(Node.s32('id', rprofile.get_int('extid'))) + r.add_child(Node.s32('id', rprofile.extid)) r.add_child(Node.string('name', rprofile.get_str('name'))) r.add_child(Node.s32('icon', rprofile.get_dict('config').get_int('icon_id'))) r.add_child(Node.s32('class', rprofile.get_int('class'))) @@ -647,7 +647,7 @@ class ReflecBeatVolzza2(ReflecBeatVolzzaBase): rec = Node.void('rec') mycourse_f.add_child(rec) - rec.add_child(Node.s32('rival_id', rprofile.get_int('extid'))) + rec.add_child(Node.s32('rival_id', rprofile.extid)) rec.add_child(Node.s16('mycourse_id', 1)) rec.add_child(Node.s32('music_id_1', mycoursedict.get_int('music_id_1', -1))) rec.add_child(Node.s16('note_grade_1', mycoursedict.get_int('note_grade_1', -1))) @@ -665,7 +665,7 @@ class ReflecBeatVolzza2(ReflecBeatVolzzaBase): return root - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: game_config = self.get_game_config() newprofile = copy.deepcopy(oldprofile) @@ -768,8 +768,8 @@ class ReflecBeatVolzza2(ReflecBeatVolzzaBase): # 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")}') + if extid != newprofile.extid: + raise Exception(f'Unexpected user ID, got {extid} expecting {newprofile.extid}') episode_type = child.child_value('type') episode_value0 = child.child_value('value0') diff --git a/bemani/backend/reflec/volzzabase.py b/bemani/backend/reflec/volzzabase.py index 74a0aac..fc7c46b 100644 --- a/bemani/backend/reflec/volzzabase.py +++ b/bemani/backend/reflec/volzzabase.py @@ -2,7 +2,7 @@ from typing import Dict, List, Tuple from bemani.backend.reflec.base import ReflecBeatBase -from bemani.common import ID, Time, ValidatedDict +from bemani.common import ID, Time, Profile from bemani.data import Attempt, UserID from bemani.protocol import Node @@ -135,7 +135,7 @@ class ReflecBeatVolzzaBase(ReflecBeatBase): data = Node.void('data') rootnode.add_child(data) data.add_child(Node.s16('day_id', int((Time.now() - timeoffset) / Time.SECONDS_IN_DAY))) - data.add_child(Node.s32('user_id', profile.get_int('extid'))) + data.add_child(Node.s32('user_id', profile.extid)) data.add_child(Node.s16('icon_id', profile.get_dict('config').get_int('icon_id'))) data.add_child(Node.s16('point', min(points_by_user.get(userid, 0), 32767))) data.add_child(Node.s32('update_time', Time.now())) @@ -206,7 +206,7 @@ class ReflecBeatVolzzaBase(ReflecBeatBase): root.add_child(shop_score) shop_score.add_child(Node.s32('time', Time.now())) - profiles: Dict[UserID, ValidatedDict] = {} + profiles: Dict[UserID, Profile] = {} for songid in range(start_music_id, end_music_id + 1): allscores = self.data.local.music.get_all_scores( self.game, @@ -238,7 +238,7 @@ class ReflecBeatVolzzaBase(ReflecBeatBase): data.add_child(Node.s16('music_id', songid)) data.add_child(Node.s8('note_grade', score.chart)) data.add_child(Node.s8('clear_type', self._db_to_game_clear_type(score.data.get_int('clear_type')))) - data.add_child(Node.s32('user_id', profile.get_int('extid'))) + data.add_child(Node.s32('user_id', profile.extid)) data.add_child(Node.s16('icon_id', profile.get_dict('config').get_int('icon_id'))) data.add_child(Node.s32('score', score.points)) data.add_child(Node.s32('time', score.timestamp)) @@ -291,7 +291,7 @@ class ReflecBeatVolzzaBase(ReflecBeatBase): 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.s32('uid', profile.extid)) e.add_child(Node.s32('uattr', profile.get_int('uattr'))) e.add_child(Node.string('pn', profile.get_str('name'))) e.add_child(Node.s32('plyid', info.get_int('id'))) @@ -345,7 +345,7 @@ class ReflecBeatVolzzaBase(ReflecBeatBase): 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.s32('uid', profile.extid)) e.add_child(Node.s32('uattr', profile.get_int('uattr'))) e.add_child(Node.string('pn', profile.get_str('name'))) e.add_child(Node.s32('plyid', info.get_int('id'))) diff --git a/bemani/backend/sdvx/base.py b/bemani/backend/sdvx/base.py index 704e619..02b1e33 100644 --- a/bemani/backend/sdvx/base.py +++ b/bemani/backend/sdvx/base.py @@ -3,7 +3,7 @@ from typing import Dict, Optional from bemani.backend.base import Base from bemani.backend.core import CoreHandler, CardManagerHandler, PASELIHandler -from bemani.common import ValidatedDict, GameConstants, DBConstants, Parallel +from bemani.common import Profile, ValidatedDict, GameConstants, DBConstants, Parallel from bemani.data import UserID from bemani.protocol import Node @@ -78,24 +78,27 @@ class SoundVoltexBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): # First, create and save the default profile userid = self.data.remote.user.from_refid(self.game, self.version, refid) - defaultprofile = ValidatedDict({ - 'name': name, - 'loc': locid, - }) - self.put_profile(userid, defaultprofile) - - # Now, reload and format the profile, looking up the has old version flag - profile = self.get_profile(userid) + profile = Profile( + self.game, + self.version, + refid, + 0, + { + 'name': name, + 'loc': locid, + }, + ) + self.put_profile(userid, profile) return self.format_profile(userid, profile) - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> 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') - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: """ Base handler for profile parsing. Given a request and an old profile, return a new profile that's been updated with the contents of the request. diff --git a/bemani/backend/sdvx/booth.py b/bemani/backend/sdvx/booth.py index 57c9cae..bbf0f1d 100644 --- a/bemani/backend/sdvx/booth.py +++ b/bemani/backend/sdvx/booth.py @@ -4,7 +4,7 @@ from typing import Any, Dict, Optional, Tuple from bemani.backend.ess import EventLogHandler from bemani.backend.sdvx.base import SoundVoltexBase -from bemani.common import ValidatedDict, VersionConstants, ID, intish +from bemani.common import Profile, VersionConstants, ID, intish from bemani.data import Score, UserID from bemani.protocol import Node @@ -430,12 +430,12 @@ class SoundVoltexBooth( game.add_child(Node.s8('result', result)) return game - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: game = Node.void('game') # Generic profile stuff game.add_child(Node.string('name', profile.get_str('name'))) - game.add_child(Node.string('code', ID.format_extid(profile.get_int('extid')))) + game.add_child(Node.string('code', ID.format_extid(profile.extid))) game.add_child(Node.u32('gamecoin_packet', profile.get_int('packet'))) game.add_child(Node.u32('gamecoin_block', profile.get_int('block'))) game.add_child(Node.u32('exp_point', profile.get_int('exp'))) @@ -469,7 +469,7 @@ class SoundVoltexBooth( return game - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) # Update experience and in-game currencies diff --git a/bemani/backend/sdvx/gravitywars_s1.py b/bemani/backend/sdvx/gravitywars_s1.py index 7a8b40b..93f3491 100644 --- a/bemani/backend/sdvx/gravitywars_s1.py +++ b/bemani/backend/sdvx/gravitywars_s1.py @@ -3,7 +3,7 @@ import copy from typing import Any, Dict, List from bemani.backend.sdvx.gravitywars import SoundVoltexGravityWars -from bemani.common import ID, Time, ValidatedDict +from bemani.common import ID, Time, Profile from bemani.data import UserID from bemani.protocol import Node @@ -3081,7 +3081,7 @@ class SoundVoltexGravityWarsSeason1( info.add_child(Node.u32('id', score.id)) info.add_child(Node.u32('type', score.chart)) info.add_child(Node.string('name', profile.get_str('name'))) - info.add_child(Node.string('code', ID.format_extid(profile.get_int('extid')))) + info.add_child(Node.string('code', ID.format_extid(profile.extid))) info.add_child(Node.u32('score', score.points)) # Add to global scores @@ -3111,7 +3111,7 @@ class SoundVoltexGravityWarsSeason1( info.add_child(Node.u32('id', score.id)) info.add_child(Node.u32('type', score.chart)) info.add_child(Node.string('name', profile.get_str('name'))) - info.add_child(Node.string('code', ID.format_extid(profile.get_int('extid')))) + info.add_child(Node.string('code', ID.format_extid(profile.extid))) info.add_child(Node.u32('score', score.points)) # Add to global scores @@ -3134,12 +3134,12 @@ class SoundVoltexGravityWarsSeason1( return game - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: game = Node.void('game_3') # Generic profile stuff game.add_child(Node.string('name', profile.get_str('name'))) - game.add_child(Node.string('code', ID.format_extid(profile.get_int('extid')))) + game.add_child(Node.string('code', ID.format_extid(profile.extid))) game.add_child(Node.u32('gamecoin_packet', profile.get_int('packet'))) game.add_child(Node.u32('gamecoin_block', profile.get_int('block'))) game.add_child(Node.s16('skill_name_id', profile.get_int('skill_name_id', -1))) @@ -3272,7 +3272,7 @@ class SoundVoltexGravityWarsSeason1( return game - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) # Update blaster energy and in-game currencies diff --git a/bemani/backend/sdvx/gravitywars_s2.py b/bemani/backend/sdvx/gravitywars_s2.py index d0a8ed8..1432982 100644 --- a/bemani/backend/sdvx/gravitywars_s2.py +++ b/bemani/backend/sdvx/gravitywars_s2.py @@ -3,7 +3,7 @@ import copy from typing import Any, Dict, List, Tuple from bemani.backend.sdvx.gravitywars import SoundVoltexGravityWars -from bemani.common import ID, Time, ValidatedDict +from bemani.common import ID, Time, Profile from bemani.data import Score, UserID from bemani.protocol import Node @@ -3905,7 +3905,7 @@ class SoundVoltexGravityWarsSeason2( highscores.add_child(info) info.add_child(Node.u32('id', musicid)) info.add_child(Node.u32('ty', chart)) - info.add_child(Node.string('a_sq', ID.format_extid(global_profile.get_int('extid')))) + info.add_child(Node.string('a_sq', ID.format_extid(global_profile.extid))) info.add_child(Node.string('a_nm', global_profile.get_str('name'))) info.add_child(Node.u32('a_sc', globalscore.points)) info.add_child(Node.s32('cr', int(clear_rate * 10000))) @@ -3913,7 +3913,7 @@ class SoundVoltexGravityWarsSeason2( if 'area' in records[musicid][chart]: (localuserid, localscore) = records[musicid][chart]['area'] local_profile = users[localuserid] - info.add_child(Node.string('l_sq', ID.format_extid(local_profile.get_int('extid')))) + info.add_child(Node.string('l_sq', ID.format_extid(local_profile.extid))) info.add_child(Node.string('l_nm', local_profile.get_str('name'))) info.add_child(Node.u32('l_sc', localscore.points)) @@ -3941,7 +3941,7 @@ class SoundVoltexGravityWarsSeason2( rival = Node.void('rival') game.add_child(rival) rival.add_child(Node.s16('no', index)) - rival.add_child(Node.string('seq', ID.format_extid(other_profile.get_int('extid')))) + rival.add_child(Node.string('seq', ID.format_extid(other_profile.extid))) rival.add_child(Node.string('name', other_profile.get_str('name'))) # Return scores for this user on random charts @@ -3955,12 +3955,12 @@ class SoundVoltexGravityWarsSeason2( return game - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: game = Node.void('game_3') # Generic profile stuff game.add_child(Node.string('name', profile.get_str('name'))) - game.add_child(Node.string('code', ID.format_extid(profile.get_int('extid')))) + game.add_child(Node.string('code', ID.format_extid(profile.extid))) game.add_child(Node.u32('gamecoin_packet', profile.get_int('packet'))) game.add_child(Node.u32('gamecoin_block', profile.get_int('block'))) game.add_child(Node.s16('skill_name_id', profile.get_int('chosen_skill_id', profile.get_int('skill_name_id', -1)))) @@ -4134,7 +4134,7 @@ class SoundVoltexGravityWarsSeason2( return game - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) # Update blaster energy and in-game currencies diff --git a/bemani/backend/sdvx/heavenlyhaven.py b/bemani/backend/sdvx/heavenlyhaven.py index 2028003..3e2fbae 100644 --- a/bemani/backend/sdvx/heavenlyhaven.py +++ b/bemani/backend/sdvx/heavenlyhaven.py @@ -5,7 +5,7 @@ from typing import Any, Dict, List, Optional, Tuple from bemani.backend.ess import EventLogHandler from bemani.backend.sdvx.base import SoundVoltexBase from bemani.backend.sdvx.gravitywars import SoundVoltexGravityWars -from bemani.common import ID, Time, ValidatedDict, VersionConstants +from bemani.common import ID, Time, Profile, VersionConstants from bemani.data import Score, UserID from bemani.protocol import Node @@ -3470,7 +3470,7 @@ class SoundVoltexHeavenlyHaven( highscores.add_child(info) info.add_child(Node.u32('id', musicid)) info.add_child(Node.u32('ty', chart)) - info.add_child(Node.string('a_sq', ID.format_extid(global_profile.get_int('extid')))) + info.add_child(Node.string('a_sq', ID.format_extid(global_profile.extid))) info.add_child(Node.string('a_nm', global_profile.get_str('name'))) info.add_child(Node.u32('a_sc', globalscore.points)) info.add_child(Node.s32('cr', int(clear_rate * 10000))) @@ -3479,7 +3479,7 @@ class SoundVoltexHeavenlyHaven( if 'area' in records[musicid][chart]: (localuserid, localscore) = records[musicid][chart]['area'] local_profile = users[localuserid] - info.add_child(Node.string('l_sq', ID.format_extid(local_profile.get_int('extid')))) + info.add_child(Node.string('l_sq', ID.format_extid(local_profile.extid))) info.add_child(Node.string('l_nm', local_profile.get_str('name'))) info.add_child(Node.u32('l_sc', localscore.points)) @@ -3604,7 +3604,7 @@ class SoundVoltexHeavenlyHaven( rival = Node.void('rival') game.add_child(rival) rival.add_child(Node.s16('no', index)) - rival.add_child(Node.string('seq', ID.format_extid(other_profile.get_int('extid')))) + rival.add_child(Node.string('seq', ID.format_extid(other_profile.extid))) rival.add_child(Node.string('name', other_profile.get_str('name'))) # Keep track of index @@ -3841,13 +3841,13 @@ class SoundVoltexHeavenlyHaven( # Return a blank response return Node.void('game') - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: game = Node.void('game') # Generic profile stuff game.add_child(Node.string('name', profile.get_str('name'))) - game.add_child(Node.string('code', ID.format_extid(profile.get_int('extid')))) - game.add_child(Node.string('sdvx_id', ID.format_extid(profile.get_int('extid')))) + game.add_child(Node.string('code', ID.format_extid(profile.extid))) + game.add_child(Node.string('sdvx_id', ID.format_extid(profile.extid))) game.add_child(Node.u16('appeal_id', profile.get_int('appealid'))) game.add_child(Node.s16('skill_base_id', profile.get_int('skill_base_id'))) game.add_child(Node.s16('skill_name_id', profile.get_int('skill_name_id'))) @@ -4035,7 +4035,7 @@ class SoundVoltexHeavenlyHaven( return game - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) # Update blaster energy and in-game currencies diff --git a/bemani/backend/sdvx/infiniteinfection.py b/bemani/backend/sdvx/infiniteinfection.py index 9630216..913557b 100644 --- a/bemani/backend/sdvx/infiniteinfection.py +++ b/bemani/backend/sdvx/infiniteinfection.py @@ -5,7 +5,7 @@ from typing import Any, Dict, List, Optional from bemani.backend.ess import EventLogHandler from bemani.backend.sdvx.base import SoundVoltexBase from bemani.backend.sdvx.booth import SoundVoltexBooth -from bemani.common import Time, ValidatedDict, VersionConstants, ID +from bemani.common import Time, Profile, VersionConstants, ID from bemani.data import UserID from bemani.protocol import Node @@ -1993,7 +1993,7 @@ class SoundVoltexInfiniteInfection( info.add_child(Node.u32('id', score.id)) info.add_child(Node.u32('type', score.chart)) info.add_child(Node.string('name', profile.get_str('name'))) - info.add_child(Node.string('code', ID.format_extid(profile.get_int('extid')))) + info.add_child(Node.string('code', ID.format_extid(profile.extid))) info.add_child(Node.u32('score', score.points)) # Add to global scores @@ -2023,7 +2023,7 @@ class SoundVoltexInfiniteInfection( info.add_child(Node.u32('id', score.id)) info.add_child(Node.u32('type', score.chart)) info.add_child(Node.string('name', profile.get_str('name'))) - info.add_child(Node.string('code', ID.format_extid(profile.get_int('extid')))) + info.add_child(Node.string('code', ID.format_extid(profile.extid))) info.add_child(Node.u32('score', score.points)) # Add to local scores @@ -2289,12 +2289,12 @@ class SoundVoltexInfiniteInfection( game.add_child(Node.s8('result', result)) return game - def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: + def format_profile(self, userid: UserID, profile: Profile) -> Node: game = Node.void('game_2') # Generic profile stuff game.add_child(Node.string('name', profile.get_str('name'))) - game.add_child(Node.string('code', ID.format_extid(profile.get_int('extid')))) + game.add_child(Node.string('code', ID.format_extid(profile.extid))) game.add_child(Node.u32('gamecoin_packet', profile.get_int('packet'))) game.add_child(Node.u32('gamecoin_block', profile.get_int('block'))) game.add_child(Node.s16('skill_name_id', profile.get_int('skill_name_id', -1))) @@ -2424,7 +2424,7 @@ class SoundVoltexInfiniteInfection( return game - def unformat_profile(self, userid: UserID, request: Node, oldprofile: ValidatedDict) -> ValidatedDict: + def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile: newprofile = copy.deepcopy(oldprofile) # Update blaster energy and in-game currencies diff --git a/bemani/common/__init__.py b/bemani/common/__init__.py index e1f3416..9a44aef 100644 --- a/bemani/common/__init__.py +++ b/bemani/common/__init__.py @@ -1,5 +1,5 @@ from bemani.common.model import Model -from bemani.common.validateddict import ValidatedDict, intish +from bemani.common.validateddict import ValidatedDict, Profile, intish from bemani.common.http import HTTP from bemani.common.constants import APIConstants, GameConstants, VersionConstants, DBConstants, BroadcastConstants from bemani.common.card import CardCipher, CardCipherException @@ -13,6 +13,7 @@ from bemani.common.pe import PEFile __all__ = [ "Model", "ValidatedDict", + "Profile", "HTTP", "APIConstants", "GameConstants", diff --git a/bemani/common/validateddict.py b/bemani/common/validateddict.py index 4e3092e..272bba7 100644 --- a/bemani/common/validateddict.py +++ b/bemani/common/validateddict.py @@ -1,5 +1,7 @@ from typing import Optional, List, Dict, Any +from bemani.common.constants import GameConstants + def intish(val: Any, base: int=10) -> Optional[int]: if val is None: @@ -437,3 +439,18 @@ class ValidatedDict(dict): self[name] = 1 else: self[name] = self[name] + 1 + + +class Profile(ValidatedDict): + """ + A special case of a ValidatedDict, a profile is guaranteed to also contain + references to how it was created or loaded, including the game/version + combo and the refid and extid associated wit the profile. + """ + + def __init__(self, game: GameConstants, version: int, refid: str, extid: int, initial_values: Dict[str, Any] = {}) -> None: + super().__init__(initial_values or {}) + self.game = game + self.version = version + self.refid = refid + self.extid = extid diff --git a/bemani/data/api/user.py b/bemani/data/api/user.py index f98c754..1650602 100644 --- a/bemani/data/api/user.py +++ b/bemani/data/api/user.py @@ -1,7 +1,6 @@ -import copy -from typing import List, Tuple, Optional, Dict, Any +from typing import List, Tuple, Optional -from bemani.common import APIConstants, GameConstants, ValidatedDict, Parallel +from bemani.common import APIConstants, GameConstants, Profile, Parallel from bemani.data.interfaces import APIProviderInterface from bemani.data.api.base import BaseGlobalData from bemani.data.mysql.user import UserData @@ -15,25 +14,20 @@ class GlobalUserData(BaseGlobalData): super().__init__(api) self.user = user - def __format_ddr_profile(self, profile: ValidatedDict) -> Dict[str, Any]: - updates = {} - + def __format_ddr_profile(self, updates: Profile, profile: Profile) -> None: area = profile.get_int('area', -1) if area != -1: updates['area'] = area - return updates - - def __format_iidx_profile(self, profile: ValidatedDict) -> Dict[str, Any]: - updates: Dict[str, Any] = { - 'qpro': {}, - } + def __format_iidx_profile(self, updates: Profile, profile: Profile) -> None: area = profile.get_int('area', -1) if area != -1: updates['pid'] = area qpro = profile.get_dict('qpro') + updates['qpro'] = {} + head = qpro.get_int('head', -1) if head != -1: updates['qpro']['head'] = head @@ -50,62 +44,54 @@ class GlobalUserData(BaseGlobalData): if hand != -1: updates['qpro']['hand'] = hand - return updates + def __format_jubeat_profile(self, updates: Profile, profile: Profile) -> None: + pass - def __format_jubeat_profile(self, profile: ValidatedDict) -> Dict[str, Any]: - return {} - - def __format_museca_profile(self, profile: ValidatedDict) -> Dict[str, Any]: - return {} - - def __format_popn_profile(self, profile: ValidatedDict) -> Dict[str, Any]: - updates = {} + def __format_museca_profile(self, updates: Profile, profile: Profile) -> None: + pass + def __format_popn_profile(self, updates: Profile, profile: Profile) -> None: chara = profile.get_int('character', -1) if chara != -1: updates['chara'] = chara - return updates - - def __format_reflec_profile(self, profile: ValidatedDict) -> Dict[str, Any]: - updates = {} - + def __format_reflec_profile(self, updates: Profile, profile: Profile) -> None: icon = profile.get_int('icon', -1) if icon != -1: updates['config'] = {'icon_id': icon} - return updates + def __format_sdvx_profile(self, updates: Profile, profile: Profile) -> None: + pass - def __format_sdvx_profile(self, profile: ValidatedDict) -> Dict[str, Any]: - return {} + def __format_profile(self, profile: Profile) -> Profile: + new = Profile( + profile.game, + profile.version, + profile.refid, + profile.extid, + { + 'name': profile.get('name', ''), + }, + ) - def __format_profile(self, profile: ValidatedDict) -> ValidatedDict: - base = { - 'name': profile.get('name', ''), - 'game': profile['game'], - 'version': profile['version'], - 'refid': profile['refid'], - 'extid': profile['extid'], - } + if profile.game == GameConstants.DDR: + self.__format_ddr_profile(new, profile) + if profile.game == GameConstants.IIDX: + self.__format_iidx_profile(new, profile) + if profile.game == GameConstants.JUBEAT: + self.__format_jubeat_profile(new, profile) + if profile.game == GameConstants.MUSECA: + self.__format_museca_profile(new, profile) + if profile.game == GameConstants.POPN_MUSIC: + self.__format_popn_profile(new, profile) + if profile.game == GameConstants.REFLEC_BEAT: + self.__format_reflec_profile(new, profile) + if profile.game == GameConstants.SDVX: + self.__format_sdvx_profile(new, profile) - if profile['game'] == GameConstants.DDR: - base.update(self.__format_ddr_profile(profile)) - if profile['game'] == GameConstants.IIDX: - base.update(self.__format_iidx_profile(profile)) - if profile['game'] == GameConstants.JUBEAT: - base.update(self.__format_jubeat_profile(profile)) - if profile['game'] == GameConstants.MUSECA: - base.update(self.__format_museca_profile(profile)) - if profile['game'] == GameConstants.POPN_MUSIC: - base.update(self.__format_popn_profile(profile)) - if profile['game'] == GameConstants.REFLEC_BEAT: - base.update(self.__format_reflec_profile(profile)) - if profile['game'] == GameConstants.SDVX: - base.update(self.__format_sdvx_profile(profile)) + return new - return ValidatedDict(base) - - def __profile_request(self, game: GameConstants, version: int, userid: UserID, exact: bool) -> Optional[ValidatedDict]: + def __profile_request(self, game: GameConstants, version: int, userid: UserID, exact: bool) -> Optional[Profile]: # First, get or create the extid/refid for this virtual user cardid = RemoteUser.userid_to_card(userid) refid = self.user.get_refid(game, version, userid) @@ -121,25 +107,22 @@ class GlobalUserData(BaseGlobalData): for profile in profiles: cards = [card.upper() for card in profile.get('cards', [])] if cardid in cards: - # Sanitize the returned data - profile = copy.deepcopy(profile) - del profile['cards'] - + # Don't take non-exact matches. exact_match = profile.get('match', 'partial') == 'exact' if exact and (not exact_match): # This is a partial match, not for this game/version continue - if 'match' in profile: - del profile['match'] - - # Add in our defaults we always provide - profile['game'] = game - profile['version'] = version if exact_match else 0 - profile['refid'] = refid - profile['extid'] = extid - - return self.__format_profile(ValidatedDict(profile)) + # Add in our defaults we always provide, convert it to a local format. + return self.__format_profile( + Profile( + game, + version, + refid, + extid, + profile, + ) + ) return None @@ -155,19 +138,19 @@ class GlobalUserData(BaseGlobalData): def from_extid(self, game: GameConstants, version: int, extid: int) -> Optional[UserID]: return self.user.from_extid(game, version, extid) - def get_profile(self, game: GameConstants, version: int, userid: UserID) -> Optional[ValidatedDict]: + def get_profile(self, game: GameConstants, version: int, userid: UserID) -> Optional[Profile]: if RemoteUser.is_remote(userid): return self.__profile_request(game, version, userid, exact=True) else: return self.user.get_profile(game, version, userid) - def get_any_profile(self, game: GameConstants, version: int, userid: UserID) -> Optional[ValidatedDict]: + def get_any_profile(self, game: GameConstants, version: int, userid: UserID) -> Optional[Profile]: if RemoteUser.is_remote(userid): return self.__profile_request(game, version, userid, exact=False) else: return self.user.get_any_profile(game, version, userid) - def get_any_profiles(self, game: GameConstants, version: int, userids: List[UserID]) -> List[Tuple[UserID, Optional[ValidatedDict]]]: + def get_any_profiles(self, game: GameConstants, version: int, userids: List[UserID]) -> List[Tuple[UserID, Optional[Profile]]]: if len(userids) == 0: return [] @@ -211,25 +194,24 @@ class GlobalUserData(BaseGlobalData): continue # Sanitize the returned data - profile = copy.deepcopy(profile) - del profile['cards'] - exact_match = profile.get('match', 'partial') == 'exact' - - if 'match' in profile: - del profile['match'] - refid = self.user.get_refid(game, version, userid) extid = self.user.get_extid(game, version, userid) # Add in our defaults we always provide - profile['game'] = game - profile['version'] = version if exact_match else 0 - profile['refid'] = refid - profile['extid'] = extid - local_profiles.append( - (userid, self.__format_profile(ValidatedDict(profile))), + ( + userid, + self.__format_profile( + Profile( + game, + version if exact_match else 0, + refid, + extid, + profile, + ), + ), + ), ) # Mark that we saw this card/user @@ -241,7 +223,7 @@ class GlobalUserData(BaseGlobalData): return local_profiles - def get_all_profiles(self, game: GameConstants, version: int) -> List[Tuple[UserID, ValidatedDict]]: + def get_all_profiles(self, game: GameConstants, version: int) -> List[Tuple[UserID, Profile]]: # Fetch local and remote profiles, and then merge by adding remote profiles to local # profiles when we don't have a profile for that user ID yet. local_cards, local_profiles, remote_profiles = Parallel.execute([ @@ -270,23 +252,24 @@ class GlobalUserData(BaseGlobalData): # We have a local version of this profile! continue - # Create a fake user with this profile - del profile['cards'] - exact_match = profile.get('match', 'partial') == 'exact' if not exact_match: continue + # Create a fake user with this profile userid = RemoteUser.card_to_userid(cardids[0]) refid = self.user.get_refid(game, version, userid) extid = self.user.get_extid(game, version, userid) # Add in our defaults we always provide - profile['game'] = game - profile['version'] = version - profile['refid'] = refid - profile['extid'] = extid - - id_to_profile[userid] = self.__format_profile(ValidatedDict(profile)) + id_to_profile[userid] = self.__format_profile( + Profile( + game, + version, + refid, + extid, + profile, + ), + ) return [(userid, id_to_profile[userid]) for userid in id_to_profile] diff --git a/bemani/data/mysql/lobby.py b/bemani/data/mysql/lobby.py index 1778c07..bbeeb2d 100644 --- a/bemani/data/mysql/lobby.py +++ b/bemani/data/mysql/lobby.py @@ -133,6 +133,8 @@ class LobbyData(BaseData): data = copy.deepcopy(data) if 'id' in data: del data['id'] + if 'time' in data: + del data['time'] # Add json to player session sql = ( @@ -244,6 +246,7 @@ class LobbyData(BaseData): for result in cursor.fetchall(): data = ValidatedDict(self.deserialize(result['data'])) data['id'] = result['id'] + data['time'] = result['time'] ret.append((UserID(result['userid']), data)) return ret @@ -260,6 +263,8 @@ class LobbyData(BaseData): data = copy.deepcopy(data) if 'id' in data: del data['id'] + if 'time' in data: + del data['time'] # Add json to lobby sql = ( diff --git a/bemani/data/mysql/user.py b/bemani/data/mysql/user.py index 7e8999a..263a4bd 100644 --- a/bemani/data/mysql/user.py +++ b/bemani/data/mysql/user.py @@ -1,4 +1,3 @@ -import copy import random from sqlalchemy import Table, Column, UniqueConstraint # type: ignore from sqlalchemy.types import String, Integer, JSON # type: ignore @@ -7,7 +6,7 @@ from sqlalchemy.exc import IntegrityError # type: ignore from typing import Optional, Dict, List, Tuple, Any from passlib.hash import pbkdf2_sha512 # type: ignore -from bemani.common import ValidatedDict, GameConstants, Time +from bemani.common import ValidatedDict, Profile, GameConstants, Time from bemani.data.mysql.base import BaseData, metadata from bemani.data.remoteuser import RemoteUser from bemani.data.types import User, Achievement, Link, UserID, ArcadeID @@ -476,7 +475,7 @@ class UserData(BaseData): sql = "UPDATE user SET password = :hash WHERE id = :userid" self.execute(sql, {'hash': passhash, 'userid': userid}) - def get_profile(self, game: GameConstants, version: int, userid: UserID) -> Optional[ValidatedDict]: + def get_profile(self, game: GameConstants, version: int, userid: UserID) -> Optional[Profile]: """ Given a game/version/userid, look up the associated profile. @@ -500,24 +499,24 @@ class UserData(BaseData): return None result = cursor.fetchone() - profile = { - 'refid': result['refid'], - 'extid': result['extid'], - 'game': game, - 'version': version, - } + profile = Profile( + game, + version, + result['refid'], + result['extid'], + ) sql = "SELECT data FROM profile WHERE refid = :refid" - cursor = self.execute(sql, {'refid': profile['refid']}) + cursor = self.execute(sql, {'refid': profile.refid}) if cursor.rowcount != 1: # Profile doesn't exist return None result = cursor.fetchone() profile.update(self.deserialize(result['data'])) - return ValidatedDict(profile) + return profile - def get_any_profile(self, game: GameConstants, version: int, userid: UserID) -> Optional[ValidatedDict]: + def get_any_profile(self, game: GameConstants, version: int, userid: UserID) -> Optional[Profile]: """ Given a game/version/userid, look up the associated profile. If the profile for that version doesn't exist, try another profile, failing only if there is no profile for any version of @@ -542,7 +541,7 @@ class UserData(BaseData): else: return None - def get_any_profiles(self, game: GameConstants, version: int, userids: List[UserID]) -> List[Tuple[UserID, Optional[ValidatedDict]]]: + def get_any_profiles(self, game: GameConstants, version: int, userids: List[UserID]) -> List[Tuple[UserID, Optional[Profile]]]: """ Does the exact same thing as get_any_profile but across a list of users instead of one. Provided purely as a convenience function. @@ -578,7 +577,7 @@ class UserData(BaseData): profiles.append((GameConstants(result['game']), result['version'])) return profiles - def get_all_profiles(self, game: GameConstants, version: int) -> List[Tuple[UserID, ValidatedDict]]: + def get_all_profiles(self, game: GameConstants, version: int) -> List[Tuple[UserID, Profile]]: """ Given a game/version, look up all user profiles for that game. @@ -599,17 +598,17 @@ class UserData(BaseData): profiles = [] for result in cursor.fetchall(): - profile = { - 'refid': result['refid'], - 'extid': result['extid'], - 'game': game, - 'version': version, - } + profile = Profile( + game, + version, + result['refid'], + result['extid'], + ) profile.update(self.deserialize(result['data'])) profiles.append( ( UserID(result['userid']), - ValidatedDict(profile), + profile, ) ) @@ -668,7 +667,7 @@ class UserData(BaseData): return achievements - def put_profile(self, game: GameConstants, version: int, userid: UserID, profile: Dict[str, Any]) -> None: + def put_profile(self, game: GameConstants, version: int, userid: UserID, profile: Profile) -> None: """ Given a game/version/userid, save an associated profile. @@ -679,15 +678,6 @@ class UserData(BaseData): profile - A dictionary that a game class will want to retrieve later. """ refid = self.get_refid(game, version, userid) - profile = copy.deepcopy(profile) - if 'refid' in profile: - del profile['refid'] - if 'extid' in profile: - del profile['extid'] - if 'game' in profile: - del profile['game'] - if 'version' in profile: - del profile['version'] # Add profile json to game profile sql = ( @@ -697,6 +687,13 @@ class UserData(BaseData): ) self.execute(sql, {'refid': refid, 'json': self.serialize(profile)}) + # Update profile details just in case this was a new profile that was just saved. + profile.game = game + profile.version = version + profile.refid = refid + if profile.extid == 0: + profile.extid = self.get_extid(game, version, userid) + def get_achievement(self, game: GameConstants, version: int, userid: UserID, achievementid: int, achievementtype: str) -> Optional[ValidatedDict]: """ Given a game/version/userid and achievement id/type, find that achievement. diff --git a/bemani/frontend/base.py b/bemani/frontend/base.py index 9801465..3a126a8 100644 --- a/bemani/frontend/base.py +++ b/bemani/frontend/base.py @@ -5,7 +5,7 @@ from typing import Any, Dict, Iterator, List, Optional, Set, Tuple from flask_caching import Cache # type: ignore -from bemani.common import GameConstants, ValidatedDict, ID +from bemani.common import GameConstants, Profile, ValidatedDict, ID from bemani.data import Data, Score, Attempt, Link, Song, UserID, RemoteUser @@ -67,14 +67,14 @@ class FrontendBase(ABC): 'points': attempt.points, } - def format_rival(self, link: Link, profile: ValidatedDict) -> Dict[str, Any]: + def format_rival(self, link: Link, profile: Profile) -> Dict[str, Any]: return { 'type': link.type, 'userid': str(link.other_userid), 'remote': RemoteUser.is_remote(link.other_userid), } - def format_profile(self, profile: ValidatedDict, playstats: ValidatedDict) -> Dict[str, Any]: + def format_profile(self, profile: Profile, playstats: ValidatedDict) -> Dict[str, Any]: return { 'name': profile.get_str('name'), 'extid': ID.format_extid(profile.get_int('extid')), diff --git a/bemani/frontend/bishi/bishi.py b/bemani/frontend/bishi/bishi.py index b25dbaa..d226ad4 100644 --- a/bemani/frontend/bishi/bishi.py +++ b/bemani/frontend/bishi/bishi.py @@ -5,7 +5,7 @@ from typing import Any, Dict, Iterator, Tuple from flask_caching import Cache # type: ignore from bemani.backend.bishi import BishiBashiFactory -from bemani.common import ValidatedDict, ID, GameConstants +from bemani.common import Profile, ValidatedDict, ID, GameConstants from bemani.data import Data from bemani.frontend.base import FrontendBase @@ -36,7 +36,7 @@ class BishiBashiFrontend(FrontendBase): return 'なし' return name - def update_name(self, profile: ValidatedDict, name: str) -> ValidatedDict: + def update_name(self, profile: Profile, name: str) -> Profile: newprofile = copy.deepcopy(profile) for i in range(len(newprofile['strdatas'])): strdata = newprofile['strdatas'][i] @@ -55,7 +55,7 @@ class BishiBashiFrontend(FrontendBase): return newprofile - def format_profile(self, profile: ValidatedDict, playstats: ValidatedDict) -> Dict[str, Any]: + def format_profile(self, profile: Profile, playstats: ValidatedDict) -> Dict[str, Any]: name = 'なし' # Nothing shop = '未設定' # Not set shop_area = '未設定' # Not set diff --git a/bemani/frontend/ddr/ddr.py b/bemani/frontend/ddr/ddr.py index 261206f..444b24b 100644 --- a/bemani/frontend/ddr/ddr.py +++ b/bemani/frontend/ddr/ddr.py @@ -3,7 +3,7 @@ import copy from typing import Any, Dict, Iterator, Tuple from bemani.backend.ddr import DDRFactory, DDRBase -from bemani.common import ValidatedDict, GameConstants, VersionConstants +from bemani.common import Profile, ValidatedDict, GameConstants, VersionConstants from bemani.data import Attempt, Link, RemoteUser, Score, Song, UserID from bemani.frontend.base import FrontendBase @@ -40,12 +40,12 @@ class DDRFrontend(FrontendBase): def all_games(self) -> Iterator[Tuple[GameConstants, int, str]]: yield from DDRFactory.all_games() - def update_name(self, profile: ValidatedDict, name: str) -> ValidatedDict: + def update_name(self, profile: Profile, name: str) -> Profile: newprofile = copy.deepcopy(profile) newprofile.replace_str('name', name) return newprofile - def update_weight(self, profile: ValidatedDict, weight: int, enabled: bool) -> ValidatedDict: + def update_weight(self, profile: Profile, weight: int, enabled: bool) -> Profile: newprofile = copy.deepcopy(profile) if newprofile.get_int('version') in (VersionConstants.DDR_ACE, VersionConstants.DDR_A20): if enabled: @@ -62,17 +62,17 @@ class DDRFrontend(FrontendBase): del newprofile['weight'] return newprofile - def update_early_late(self, profile: ValidatedDict, display_early_late: bool) -> ValidatedDict: + def update_early_late(self, profile: Profile, display_early_late: bool) -> Profile: newprofile = copy.deepcopy(profile) newprofile.replace_int('early_late', 1 if display_early_late else 0) return newprofile - def update_background_combo(self, profile: ValidatedDict, background_combo: bool) -> ValidatedDict: + def update_background_combo(self, profile: Profile, background_combo: bool) -> Profile: newprofile = copy.deepcopy(profile) newprofile.replace_int('combo', 1 if background_combo else 0) return newprofile - def update_settings(self, profile: ValidatedDict, new_settings: Dict[str, Any]) -> ValidatedDict: + def update_settings(self, profile: Profile, new_settings: Dict[str, Any]) -> Profile: newprofile = copy.deepcopy(profile) if newprofile.get_int('version') in (VersionConstants.DDR_ACE, VersionConstants.DDR_A20): newprofile.replace_int('arrowskin', new_settings['arrowskin']) @@ -84,7 +84,7 @@ class DDRFrontend(FrontendBase): pass return newprofile - def format_profile(self, profile: ValidatedDict, playstats: ValidatedDict) -> Dict[str, Any]: + def format_profile(self, profile: Profile, playstats: ValidatedDict) -> Dict[str, Any]: formatted_profile = super().format_profile(profile, playstats) if profile.get_int('version') in (VersionConstants.DDR_ACE, VersionConstants.DDR_A20): formatted_profile.update({ @@ -200,7 +200,7 @@ class DDRFrontend(FrontendBase): new_song['difficulties'][new.chart] = new.data.get_int('difficulty', 20) return new_song - def activate_rival(self, profile: ValidatedDict, position: int) -> ValidatedDict: + def activate_rival(self, profile: Profile, position: int) -> Profile: newprofile = copy.deepcopy(profile) if newprofile.get_int('version') == VersionConstants.DDR_X2: # X2 only has one active rival @@ -219,7 +219,7 @@ class DDRFrontend(FrontendBase): newprofile.replace_dict('last', lastdict) return newprofile - def deactivate_rival(self, profile: ValidatedDict, position: int) -> ValidatedDict: + def deactivate_rival(self, profile: Profile, position: int) -> Profile: newprofile = copy.deepcopy(profile) if newprofile.get_int('version') == VersionConstants.DDR_X2: # X2 only has one active rival @@ -239,11 +239,17 @@ class DDRFrontend(FrontendBase): newprofile.replace_dict('last', lastdict) return newprofile - def format_rival(self, link: Link, profile: ValidatedDict) -> Dict[str, Any]: + def format_rival(self, link: Link, profile: Profile) -> Dict[str, Any]: pos = int(link.type[7:]) if profile.get_int('version') == VersionConstants.DDR_X2: active = pos == (profile.get_dict('last').get_int('fri') - 1) - elif profile.get_int('version') in [VersionConstants.DDR_X3_VS_2NDMIX, VersionConstants.DDR_2013, VersionConstants.DDR_2014, VersionConstants.DDR_ACE, VersionConstants.DDR_A20]: + elif profile.get_int('version') in { + VersionConstants.DDR_X3_VS_2NDMIX, + VersionConstants.DDR_2013, + VersionConstants.DDR_2014, + VersionConstants.DDR_ACE, + VersionConstants.DDR_A20 + }: actives = [ profile.get_dict('last').get_int('rival1') - 1, profile.get_dict('last').get_int('rival2') - 1, diff --git a/bemani/frontend/iidx/iidx.py b/bemani/frontend/iidx/iidx.py index 000bd19..f6c6b1d 100644 --- a/bemani/frontend/iidx/iidx.py +++ b/bemani/frontend/iidx/iidx.py @@ -4,7 +4,7 @@ from typing import Any, Dict, Iterator, Optional, Tuple, List from flask_caching import Cache # type: ignore from bemani.backend.iidx import IIDXFactory, IIDXBase -from bemani.common import ValidatedDict, GameConstants +from bemani.common import Profile, ValidatedDict, GameConstants from bemani.data import Attempt, Data, Score, Song, UserID from bemani.frontend.base import FrontendBase @@ -185,7 +185,7 @@ class IIDXFrontend(FrontendBase): ], } - def format_profile(self, profile: ValidatedDict, playstats: ValidatedDict) -> Dict[str, Any]: + def format_profile(self, profile: Profile, playstats: ValidatedDict) -> Dict[str, Any]: formatted_profile = super().format_profile(profile, playstats) formatted_profile.update({ 'arcade': "", diff --git a/bemani/frontend/jubeat/jubeat.py b/bemani/frontend/jubeat/jubeat.py index 2a138bb..b2749e8 100644 --- a/bemani/frontend/jubeat/jubeat.py +++ b/bemani/frontend/jubeat/jubeat.py @@ -2,7 +2,7 @@ from typing import Any, Dict, Iterator, Tuple from bemani.backend.jubeat import JubeatFactory, JubeatBase -from bemani.common import ValidatedDict, GameConstants, VersionConstants +from bemani.common import Profile, ValidatedDict, GameConstants, VersionConstants from bemani.data import Attempt, Score, Song, UserID from bemani.frontend.base import FrontendBase @@ -67,7 +67,7 @@ class JubeatFrontend(FrontendBase): }.get(attempt.data.get_int('medal'), 'NO PLAY') return formatted_attempt - def format_profile(self, profile: ValidatedDict, playstats: ValidatedDict) -> Dict[str, Any]: + def format_profile(self, profile: Profile, playstats: ValidatedDict) -> Dict[str, Any]: formatted_profile = super().format_profile(profile, playstats) formatted_profile['plays'] = playstats.get_int('total_plays') return formatted_profile diff --git a/bemani/frontend/museca/museca.py b/bemani/frontend/museca/museca.py index 5e12305..aff0f19 100644 --- a/bemani/frontend/museca/museca.py +++ b/bemani/frontend/museca/museca.py @@ -4,7 +4,7 @@ from typing import Any, Dict, Iterator, Tuple from flask_caching import Cache # type: ignore from bemani.backend.museca import MusecaFactory, MusecaBase -from bemani.common import GameConstants, VersionConstants, DBConstants, ValidatedDict +from bemani.common import GameConstants, VersionConstants, DBConstants, Profile, ValidatedDict from bemani.data import Attempt, Data, Score, Song, UserID from bemani.frontend.base import FrontendBase @@ -74,7 +74,7 @@ class MusecaFrontend(FrontendBase): formatted_attempt['medal'] = attempt.data.get_int('clear_type') return formatted_attempt - def format_profile(self, profile: ValidatedDict, playstats: ValidatedDict) -> Dict[str, Any]: + def format_profile(self, profile: Profile, playstats: ValidatedDict) -> Dict[str, Any]: formatted_profile = super().format_profile(profile, playstats) formatted_profile['plays'] = playstats.get_int('total_plays') return formatted_profile diff --git a/bemani/frontend/popn/popn.py b/bemani/frontend/popn/popn.py index 347aa8b..570cd3c 100644 --- a/bemani/frontend/popn/popn.py +++ b/bemani/frontend/popn/popn.py @@ -2,7 +2,7 @@ from typing import Any, Dict, Iterator, Tuple from bemani.backend.popn import PopnMusicFactory, PopnMusicBase -from bemani.common import ValidatedDict, GameConstants, VersionConstants +from bemani.common import Profile, ValidatedDict, GameConstants, VersionConstants from bemani.data import Attempt, Score, Song, UserID from bemani.frontend.base import FrontendBase @@ -73,7 +73,7 @@ class PopnMusicFrontend(FrontendBase): }.get(attempt.data.get_int('medal'), 'No Play') return formatted_attempt - def format_profile(self, profile: ValidatedDict, playstats: ValidatedDict) -> Dict[str, Any]: + def format_profile(self, profile: Profile, playstats: ValidatedDict) -> Dict[str, Any]: formatted_profile = super().format_profile(profile, playstats) formatted_profile['plays'] = playstats.get_int('total_plays') return formatted_profile diff --git a/bemani/frontend/reflec/reflec.py b/bemani/frontend/reflec/reflec.py index b63660a..7499c51 100644 --- a/bemani/frontend/reflec/reflec.py +++ b/bemani/frontend/reflec/reflec.py @@ -4,7 +4,7 @@ from typing import Any, Dict, Iterator, Tuple from flask_caching import Cache # type: ignore from bemani.backend.reflec import ReflecBeatFactory, ReflecBeatBase -from bemani.common import GameConstants, ValidatedDict +from bemani.common import GameConstants, Profile, ValidatedDict from bemani.data import Attempt, Data, Score, Song, UserID from bemani.frontend.base import FrontendBase @@ -74,7 +74,7 @@ class ReflecBeatFrontend(FrontendBase): formatted_attempt['medal'] = attempt.data.get_int('combo_type') * 1000 + attempt.data.get_int('clear_type') return formatted_attempt - def format_profile(self, profile: ValidatedDict, playstats: ValidatedDict) -> Dict[str, Any]: + def format_profile(self, profile: Profile, playstats: ValidatedDict) -> Dict[str, Any]: formatted_profile = super().format_profile(profile, playstats) formatted_profile['plays'] = playstats.get_int('total_plays') return formatted_profile diff --git a/bemani/frontend/sdvx/sdvx.py b/bemani/frontend/sdvx/sdvx.py index 8a65f96..6c4ebbc 100644 --- a/bemani/frontend/sdvx/sdvx.py +++ b/bemani/frontend/sdvx/sdvx.py @@ -4,7 +4,7 @@ from typing import Any, Dict, Iterator, Tuple from flask_caching import Cache # type: ignore from bemani.backend.sdvx import SoundVoltexFactory, SoundVoltexBase -from bemani.common import GameConstants, ValidatedDict +from bemani.common import GameConstants, Profile, ValidatedDict from bemani.data import Attempt, Data, Score, Song, UserID from bemani.frontend.base import FrontendBase @@ -85,7 +85,7 @@ class SoundVoltexFrontend(FrontendBase): formatted_attempt['medal'] = attempt.data.get_int('clear_type') return formatted_attempt - def format_profile(self, profile: ValidatedDict, playstats: ValidatedDict) -> Dict[str, Any]: + def format_profile(self, profile: Profile, playstats: ValidatedDict) -> Dict[str, Any]: formatted_profile = super().format_profile(profile, playstats) formatted_profile['plays'] = playstats.get_int('total_plays') return formatted_profile diff --git a/bemani/tests/test_JubeatProp.py b/bemani/tests/test_JubeatProp.py index 1236446..6b1c399 100644 --- a/bemani/tests/test_JubeatProp.py +++ b/bemani/tests/test_JubeatProp.py @@ -3,7 +3,7 @@ import unittest from unittest.mock import Mock from bemani.backend.jubeat.prop import JubeatProp -from bemani.common import ValidatedDict +from bemani.common import Profile from bemani.data.types import Achievement, UserID @@ -171,7 +171,7 @@ class TestJubeatProp(unittest.TestCase): JubeatProp._get_league_scores( data, 999, - [(UserID(1337), ValidatedDict())], + [(UserID(1337), Profile(JubeatProp.game, JubeatProp.version, "", 0))], ), ( [(1337, 1368)], @@ -193,7 +193,7 @@ class TestJubeatProp(unittest.TestCase): JubeatProp._get_league_scores( data, 999, - [(UserID(1337), ValidatedDict())], + [(UserID(1337), Profile(JubeatProp.game, JubeatProp.version, "", 0))], ), ( [], @@ -324,10 +324,16 @@ class TestJubeatProp(unittest.TestCase): data.local.user = Mock() # Test demoting a user at the bottom does nothing. - data.local.user.get_profile = Mock(return_value=ValidatedDict({ - 'league_class': 1, - 'league_subclass': 5, - })) + data.local.user.get_profile = Mock(return_value=Profile( + JubeatProp.game, + JubeatProp.version, + "", + 0, + { + 'league_class': 1, + 'league_subclass': 5, + }, + )) JubeatProp._modify_profile( data, UserID(1337), @@ -336,10 +342,16 @@ class TestJubeatProp(unittest.TestCase): self.assertFalse(data.local.user.put_profile.called) # Test promoting a user at the top does nothing. - data.local.user.get_profile = Mock(return_value=ValidatedDict({ - 'league_class': 4, - 'league_subclass': 1, - })) + data.local.user.get_profile = Mock(return_value=Profile( + JubeatProp.game, + JubeatProp.version, + "", + 0, + { + 'league_class': 4, + 'league_subclass': 1, + }, + )) JubeatProp._modify_profile( data, UserID(1337), @@ -348,11 +360,17 @@ class TestJubeatProp(unittest.TestCase): self.assertFalse(data.local.user.put_profile.called) # Test regular promotion updates profile properly - data.local.user.get_profile = Mock(return_value=ValidatedDict({ - 'league_class': 1, - 'league_subclass': 5, - 'league_is_checked': True, - })) + data.local.user.get_profile = Mock(return_value=Profile( + JubeatProp.game, + JubeatProp.version, + "", + 0, + { + 'league_class': 1, + 'league_subclass': 5, + 'league_is_checked': True, + }, + )) JubeatProp._modify_profile( data, UserID(1337), @@ -375,11 +393,17 @@ class TestJubeatProp(unittest.TestCase): data.local.user.put_profile.reset_mock() # Test regular demote updates profile properly - data.local.user.get_profile = Mock(return_value=ValidatedDict({ - 'league_class': 1, - 'league_subclass': 3, - 'league_is_checked': True, - })) + data.local.user.get_profile = Mock(return_value=Profile( + JubeatProp.game, + JubeatProp.version, + "", + 0, + { + 'league_class': 1, + 'league_subclass': 3, + 'league_is_checked': True, + }, + )) JubeatProp._modify_profile( data, UserID(1337), @@ -402,15 +426,21 @@ class TestJubeatProp(unittest.TestCase): data.local.user.put_profile.reset_mock() # Test demotion after not checking doesn't update old values - data.local.user.get_profile = Mock(return_value=ValidatedDict({ - 'league_class': 1, - 'league_subclass': 4, - 'league_is_checked': False, - 'last': { + data.local.user.get_profile = Mock(return_value=Profile( + JubeatProp.game, + JubeatProp.version, + "", + 0, + { 'league_class': 1, - 'league_subclass': 3, + 'league_subclass': 4, + 'league_is_checked': False, + 'last': { + 'league_class': 1, + 'league_subclass': 3, + }, }, - })) + )) JubeatProp._modify_profile( data, UserID(1337),