1
0
mirror of synced 2025-02-16 10:52:34 +01:00

Convert Sunny Park to modern routing method.

This commit is contained in:
Jennifer Taylor 2021-09-03 04:35:35 +00:00
parent cbbda0ef7f
commit 06d116007e

View File

@ -1,6 +1,6 @@
# vim: set fileencoding=utf-8 # vim: set fileencoding=utf-8
import copy import copy
from typing import Dict, List, Optional from typing import Dict, List
from bemani.backend.popn.base import PopnMusicBase from bemani.backend.popn.base import PopnMusicBase
from bemani.backend.popn.fantasia import PopnMusicFantasia from bemani.backend.popn.fantasia import PopnMusicFantasia
@ -43,7 +43,7 @@ class PopnMusicSunnyPark(PopnMusicBase):
# Maximum music ID for this game # Maximum music ID for this game
GAME_MAX_MUSIC_ID = 1350 GAME_MAX_MUSIC_ID = 1350
def previous_version(self) -> Optional[PopnMusicBase]: def previous_version(self) -> PopnMusicBase:
return PopnMusicFantasia(self.data, self.config, self.model) return PopnMusicFantasia(self.data, self.config, self.model)
def __format_medal_for_score(self, score: Score) -> int: def __format_medal_for_score(self, score: Score) -> int:
@ -219,7 +219,6 @@ class PopnMusicSunnyPark(PopnMusicBase):
netvs.add_child(Node.s8_array('set_recommend', [0, 0, 0])) netvs.add_child(Node.s8_array('set_recommend', [0, 0, 0]))
netvs.add_child(Node.u8('netvs_play_cnt', 0)) netvs.add_child(Node.u8('netvs_play_cnt', 0))
for dialog in [0, 1, 2, 3, 4, 5]: for dialog in [0, 1, 2, 3, 4, 5]:
# TODO: Configure this, maybe?
netvs.add_child(Node.string('dialog', f'dialog#{dialog}')) netvs.add_child(Node.string('dialog', f'dialog#{dialog}'))
sp_data = Node.void('sp_data') sp_data = Node.void('sp_data')
@ -416,191 +415,179 @@ class PopnMusicSunnyPark(PopnMusicBase):
return newprofile return newprofile
def handle_game_request(self, request: Node) -> Optional[Node]: def handle_game_get_request(self, request: Node) -> Node:
method = request.attribute('method') # TODO: Hook these up to config so we can change this
root = Node.void('game')
root.add_child(Node.s32('ir_phase', 0))
root.add_child(Node.s32('music_open_phase', 8))
root.add_child(Node.s32('collabo_phase', 8))
root.add_child(Node.s32('personal_event_phase', 10))
root.add_child(Node.s32('shop_event_phase', 6))
root.add_child(Node.s32('netvs_phase', 0))
root.add_child(Node.s32('card_phase', 9))
root.add_child(Node.s32('other_phase', 9))
root.add_child(Node.s32('local_matching_enable', 1))
root.add_child(Node.s32('n_matching_sec', 60))
root.add_child(Node.s32('l_matching_sec', 60))
root.add_child(Node.s32('is_check_cpu', 0))
root.add_child(Node.s32('week_no', 0))
root.add_child(Node.s16_array('sel_ranking', [-1, -1, -1, -1, -1]))
root.add_child(Node.s16_array('up_ranking', [-1, -1, -1, -1, -1]))
return root
if method == 'get': def handle_game_active_request(self, request: Node) -> Node:
# TODO: Hook these up to config so we can change this # Update the name of this cab for admin purposes
root = Node.void('game') self.update_machine_name(request.child_value('shop_name'))
root.add_child(Node.s32('ir_phase', 0)) return Node.void('game')
root.add_child(Node.s32('music_open_phase', 8))
root.add_child(Node.s32('collabo_phase', 8))
root.add_child(Node.s32('personal_event_phase', 10))
root.add_child(Node.s32('shop_event_phase', 6))
root.add_child(Node.s32('netvs_phase', 0))
root.add_child(Node.s32('card_phase', 9))
root.add_child(Node.s32('other_phase', 9))
root.add_child(Node.s32('local_matching_enable', 1))
root.add_child(Node.s32('n_matching_sec', 60))
root.add_child(Node.s32('l_matching_sec', 60))
root.add_child(Node.s32('is_check_cpu', 0))
root.add_child(Node.s32('week_no', 0))
root.add_child(Node.s16_array('sel_ranking', [-1, -1, -1, -1, -1]))
root.add_child(Node.s16_array('up_ranking', [-1, -1, -1, -1, -1]))
return root
if method == 'active': def handle_game_taxphase_request(self, request: Node) -> Node:
# Update the name of this cab for admin purposes return Node.void('game')
self.update_machine_name(request.child_value('shop_name'))
return Node.void('game')
if method == 'taxphase': def handle_playerdata_expire_request(self, request: Node) -> Node:
return Node.void('game') return Node.void('playerdata')
# Invalid method def handle_playerdata_logout_request(self, request: Node) -> Node:
return None return Node.void('playerdata')
def handle_playerdata_request(self, request: Node) -> Optional[Node]:
method = request.attribute('method')
if method == 'expire':
return Node.void('playerdata')
elif method == 'logout':
return Node.void('playerdata')
elif method == 'get':
modelstring = request.attribute('model')
refid = request.child_value('ref_id')
root = self.get_profile_by_refid(
refid,
self.NEW_PROFILE_ONLY if modelstring is None else self.OLD_PROFILE_ONLY,
)
if root is None:
root = Node.void('playerdata')
root.set_attribute('status', str(Status.NO_PROFILE))
return root
elif method == 'conversion':
refid = request.child_value('ref_id')
name = request.child_value('name')
chara = request.child_value('chara')
root = self.new_profile_by_refid(refid, name, chara)
if root is None:
root = Node.void('playerdata')
root.set_attribute('status', str(Status.NO_PROFILE))
return root
elif method == 'new':
refid = request.child_value('ref_id')
name = request.child_value('name')
root = self.new_profile_by_refid(refid, name)
if root is None:
root = Node.void('playerdata')
root.set_attribute('status', str(Status.NO_PROFILE))
return root
elif method == 'set':
refid = request.attribute('ref_id')
def handle_playerdata_get_request(self, request: Node) -> Node:
modelstring = request.attribute('model')
refid = request.child_value('ref_id')
root = self.get_profile_by_refid(
refid,
self.NEW_PROFILE_ONLY if modelstring is None else self.OLD_PROFILE_ONLY,
)
if root is None:
root = Node.void('playerdata') root = Node.void('playerdata')
root.add_child(Node.s8('pref', -1)) root.set_attribute('status', str(Status.NO_PROFILE))
if refid is None: return root
return root
userid = self.data.remote.user.from_refid(self.game, self.version, refid) def handle_playerdata_conversion_request(self, request: Node) -> Node:
if userid is None: refid = request.child_value('ref_id')
return root name = request.child_value('name')
chara = request.child_value('chara')
root = self.new_profile_by_refid(refid, name, chara)
if root is None:
root = Node.void('playerdata')
root.set_attribute('status', str(Status.NO_PROFILE))
return root
oldprofile = self.get_profile(userid) or Profile(self.game, self.version, refid, 0) def handle_playerdata_new_request(self, request: Node) -> Node:
newprofile = self.unformat_profile(userid, request, oldprofile) refid = request.child_value('ref_id')
name = request.child_value('name')
root = self.new_profile_by_refid(refid, name)
if root is None:
root = Node.void('playerdata')
root.set_attribute('status', str(Status.NO_PROFILE))
return root
if newprofile is not None: def handle_playerdata_set_request(self, request: Node) -> Node:
self.put_profile(userid, newprofile) refid = request.attribute('ref_id')
root.add_child(Node.string('name', newprofile['name']))
root = Node.void('playerdata')
root.add_child(Node.s8('pref', -1))
if refid is None:
return root return root
elif method == 'friend': userid = self.data.remote.user.from_refid(self.game, self.version, refid)
refid = request.attribute('ref_id') if userid is None:
root = Node.void('playerdata') return root
# Look up our own user ID based on the RefID provided. oldprofile = self.get_profile(userid) or Profile(self.game, self.version, refid, 0)
userid = self.data.remote.user.from_refid(self.game, self.version, refid) newprofile = self.unformat_profile(userid, request, oldprofile)
if userid is None:
root.set_attribute('status', str(Status.NO_PROFILE))
return root
# Grab the links that we care about. if newprofile is not None:
links = self.data.local.user.get_links(self.game, self.version, userid) self.put_profile(userid, newprofile)
profiles: Dict[UserID, Profile] = {} root.add_child(Node.string('name', newprofile['name']))
rivals: List[Link] = []
for link in links: return root
if link.type != 'rival':
def handle_playerdata_friend_request(self, request: Node) -> Node:
refid = request.attribute('ref_id')
root = Node.void('playerdata')
# Look up our own user ID based on the RefID provided.
userid = self.data.remote.user.from_refid(self.game, self.version, refid)
if userid is None:
root.set_attribute('status', str(Status.NO_PROFILE))
return root
# Grab the links that we care about.
links = self.data.local.user.get_links(self.game, self.version, userid)
profiles: Dict[UserID, Profile] = {}
rivals: List[Link] = []
for link in links:
if link.type != 'rival':
continue
other_profile = self.get_profile(link.other_userid)
if other_profile is None:
continue
profiles[link.other_userid] = other_profile
rivals.append(link)
for rival in links[:2]:
rivalid = rival.other_userid
rivalprofile = profiles[rivalid]
scores = self.data.remote.music.get_scores(self.game, self.version, rivalid)
# First, output general profile info.
friend = Node.void('friend')
root.add_child(friend)
# This might be for having non-active or non-confirmed friends, but setting to 0 makes the
# ranking numbers disappear and the player icon show a questionmark.
friend.add_child(Node.s8('open', 1))
# Set up some sane defaults.
friend.add_child(Node.string('name', rivalprofile.get_str('name', 'なし')))
friend.add_child(Node.string('g_pm_id', ID.format_extid(rivalprofile.extid)))
friend.add_child(Node.s16('chara', rivalprofile.get_int('chara', -1)))
# Set up player avatar.
avatar_dict = rivalprofile.get_dict('avatar')
friend.add_child(Node.u8('hair', avatar_dict.get_int('hair', 0)))
friend.add_child(Node.u8('face', avatar_dict.get_int('face', 0)))
friend.add_child(Node.u8('body', avatar_dict.get_int('body', 0)))
friend.add_child(Node.u8('effect', avatar_dict.get_int('effect', 0)))
friend.add_child(Node.u8('object', avatar_dict.get_int('object', 0)))
friend.add_child(Node.u8_array('comment', avatar_dict.get_int_array('comment', 2)))
# Perform hiscore/medal conversion.
hiscore_array = [0] * int((((self.GAME_MAX_MUSIC_ID * 4) * 17) + 7) / 8)
clear_medal = [0] * self.GAME_MAX_MUSIC_ID
for score in scores:
if score.id > self.GAME_MAX_MUSIC_ID:
continue continue
other_profile = self.get_profile(link.other_userid) # Skip any scores for chart types we don't support
if other_profile is None: if score.chart not in [
self.CHART_TYPE_EASY,
self.CHART_TYPE_NORMAL,
self.CHART_TYPE_HYPER,
self.CHART_TYPE_EX,
]:
continue continue
profiles[link.other_userid] = other_profile
rivals.append(link)
for rival in links[:2]: clear_medal[score.id] = clear_medal[score.id] | self.__format_medal_for_score(score)
rivalid = rival.other_userid hiscore_index = (score.id * 4) + {
rivalprofile = profiles[rivalid] self.CHART_TYPE_EASY: self.GAME_CHART_TYPE_EASY_POSITION,
scores = self.data.remote.music.get_scores(self.game, self.version, rivalid) self.CHART_TYPE_NORMAL: self.GAME_CHART_TYPE_NORMAL_POSITION,
self.CHART_TYPE_HYPER: self.GAME_CHART_TYPE_HYPER_POSITION,
self.CHART_TYPE_EX: self.GAME_CHART_TYPE_EX_POSITION,
}[score.chart]
hiscore_byte_pos = int((hiscore_index * 17) / 8)
hiscore_bit_pos = int((hiscore_index * 17) % 8)
hiscore_value = score.points << hiscore_bit_pos
hiscore_array[hiscore_byte_pos] = hiscore_array[hiscore_byte_pos] | (hiscore_value & 0xFF)
hiscore_array[hiscore_byte_pos + 1] = hiscore_array[hiscore_byte_pos + 1] | ((hiscore_value >> 8) & 0xFF)
hiscore_array[hiscore_byte_pos + 2] = hiscore_array[hiscore_byte_pos + 2] | ((hiscore_value >> 16) & 0xFF)
# First, output general profile info. hiscore = bytes(hiscore_array)
friend = Node.void('friend') friend.add_child(Node.u16_array('clear_medal', clear_medal))
root.add_child(friend) friend.add_child(Node.binary('hiscore', hiscore))
# This might be for having non-active or non-confirmed friends, but setting to 0 makes the return root
# ranking numbers disappear and the player icon show a questionmark.
friend.add_child(Node.s8('open', 1))
# Set up some sane defaults. def handle_lobby_request(self, request: Node) -> Node:
friend.add_child(Node.string('name', rivalprofile.get_str('name', 'なし')))
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.
avatar_dict = rivalprofile.get_dict('avatar')
friend.add_child(Node.u8('hair', avatar_dict.get_int('hair', 0)))
friend.add_child(Node.u8('face', avatar_dict.get_int('face', 0)))
friend.add_child(Node.u8('body', avatar_dict.get_int('body', 0)))
friend.add_child(Node.u8('effect', avatar_dict.get_int('effect', 0)))
friend.add_child(Node.u8('object', avatar_dict.get_int('object', 0)))
friend.add_child(Node.u8_array('comment', avatar_dict.get_int_array('comment', 2)))
# Perform hiscore/medal conversion.
hiscore_array = [0] * int((((self.GAME_MAX_MUSIC_ID * 4) * 17) + 7) / 8)
clear_medal = [0] * self.GAME_MAX_MUSIC_ID
for score in scores:
if score.id > self.GAME_MAX_MUSIC_ID:
continue
# Skip any scores for chart types we don't support
if score.chart not in [
self.CHART_TYPE_EASY,
self.CHART_TYPE_NORMAL,
self.CHART_TYPE_HYPER,
self.CHART_TYPE_EX,
]:
continue
clear_medal[score.id] = clear_medal[score.id] | self.__format_medal_for_score(score)
hiscore_index = (score.id * 4) + {
self.CHART_TYPE_EASY: self.GAME_CHART_TYPE_EASY_POSITION,
self.CHART_TYPE_NORMAL: self.GAME_CHART_TYPE_NORMAL_POSITION,
self.CHART_TYPE_HYPER: self.GAME_CHART_TYPE_HYPER_POSITION,
self.CHART_TYPE_EX: self.GAME_CHART_TYPE_EX_POSITION,
}[score.chart]
hiscore_byte_pos = int((hiscore_index * 17) / 8)
hiscore_bit_pos = int((hiscore_index * 17) % 8)
hiscore_value = score.points << hiscore_bit_pos
hiscore_array[hiscore_byte_pos] = hiscore_array[hiscore_byte_pos] | (hiscore_value & 0xFF)
hiscore_array[hiscore_byte_pos + 1] = hiscore_array[hiscore_byte_pos + 1] | ((hiscore_value >> 8) & 0xFF)
hiscore_array[hiscore_byte_pos + 2] = hiscore_array[hiscore_byte_pos + 2] | ((hiscore_value >> 16) & 0xFF)
hiscore = bytes(hiscore_array)
friend.add_child(Node.u16_array('clear_medal', clear_medal))
friend.add_child(Node.binary('hiscore', hiscore))
return root
# Invalid method
return None
def handle_lobby_request(self, request: Node) -> Optional[Node]:
# Stub out the entire lobby service # Stub out the entire lobby service
return Node.void('lobby') return Node.void('lobby')