2019-12-08 22:43:49 +01:00
|
|
|
|
from typing import Optional, Dict, Any, List, Tuple
|
2021-09-07 19:56:15 +02:00
|
|
|
|
from typing_extensions import Final
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
from bemani.backend.reflec.base import ReflecBeatBase
|
|
|
|
|
from bemani.backend.reflec.colette import ReflecBeatColette
|
|
|
|
|
|
2021-08-20 06:43:13 +02:00
|
|
|
|
from bemani.common import Profile, ValidatedDict, VersionConstants, ID, Time
|
2019-12-08 22:43:49 +01:00
|
|
|
|
from bemani.data import Achievement, Attempt, Score, UserID
|
|
|
|
|
from bemani.protocol import Node
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ReflecBeatGroovin(ReflecBeatBase):
|
2021-09-07 19:56:15 +02:00
|
|
|
|
name: str = "REFLEC BEAT groovin'!!"
|
|
|
|
|
version: int = VersionConstants.REFLEC_BEAT_GROOVIN
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Clear types according to the game
|
2021-09-07 19:56:15 +02:00
|
|
|
|
GAME_CLEAR_TYPE_NO_PLAY: Final[int] = 0
|
|
|
|
|
GAME_CLEAR_TYPE_EARLY_FAILED: Final[int] = 1
|
|
|
|
|
GAME_CLEAR_TYPE_FAILED: Final[int] = 2
|
|
|
|
|
GAME_CLEAR_TYPE_CLEARED: Final[int] = 9
|
|
|
|
|
GAME_CLEAR_TYPE_HARD_CLEARED: Final[int] = 10
|
|
|
|
|
GAME_CLEAR_TYPE_S_HARD_CLEARED: Final[int] = 11
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Combo types according to the game (actually a bitmask, where bit 0 is
|
|
|
|
|
# full combo status, and bit 2 is just reflec status). But we don't support
|
|
|
|
|
# saving just reflec without full combo, so we downgrade it.
|
2021-09-07 19:56:15 +02:00
|
|
|
|
GAME_COMBO_TYPE_NONE: Final[int] = 0
|
|
|
|
|
GAME_COMBO_TYPE_ALL_JUST: Final[int] = 2
|
|
|
|
|
GAME_COMBO_TYPE_FULL_COMBO: Final[int] = 1
|
|
|
|
|
GAME_COMBO_TYPE_FULL_COMBO_ALL_JUST: Final[int] = 3
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
def previous_version(self) -> Optional[ReflecBeatBase]:
|
|
|
|
|
return ReflecBeatColette(self.data, self.config, self.model)
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def get_settings(cls) -> Dict[str, Any]:
|
|
|
|
|
"""
|
|
|
|
|
Return all of our front-end modifiably settings.
|
|
|
|
|
"""
|
|
|
|
|
return {
|
2022-10-15 20:56:30 +02:00
|
|
|
|
"bools": [
|
2019-12-08 22:43:49 +01:00
|
|
|
|
{
|
2022-10-15 20:56:30 +02:00
|
|
|
|
"name": "Force Song Unlock",
|
|
|
|
|
"tip": "Force unlock all songs.",
|
|
|
|
|
"category": "game_config",
|
|
|
|
|
"setting": "force_unlock_songs",
|
2019-12-08 22:43:49 +01:00
|
|
|
|
},
|
|
|
|
|
],
|
2022-10-15 20:56:30 +02:00
|
|
|
|
"ints": [],
|
2019-12-08 22:43:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def __db_to_game_clear_type(self, db_status: int) -> int:
|
|
|
|
|
return {
|
|
|
|
|
self.CLEAR_TYPE_NO_PLAY: self.GAME_CLEAR_TYPE_NO_PLAY,
|
|
|
|
|
self.CLEAR_TYPE_FAILED: self.GAME_CLEAR_TYPE_FAILED,
|
|
|
|
|
self.CLEAR_TYPE_CLEARED: self.GAME_CLEAR_TYPE_CLEARED,
|
|
|
|
|
self.CLEAR_TYPE_HARD_CLEARED: self.GAME_CLEAR_TYPE_HARD_CLEARED,
|
|
|
|
|
self.CLEAR_TYPE_S_HARD_CLEARED: self.GAME_CLEAR_TYPE_S_HARD_CLEARED,
|
|
|
|
|
}[db_status]
|
|
|
|
|
|
|
|
|
|
def __game_to_db_clear_type(self, status: int) -> int:
|
|
|
|
|
return {
|
|
|
|
|
self.GAME_CLEAR_TYPE_NO_PLAY: self.CLEAR_TYPE_NO_PLAY,
|
|
|
|
|
self.GAME_CLEAR_TYPE_EARLY_FAILED: self.CLEAR_TYPE_FAILED,
|
|
|
|
|
self.GAME_CLEAR_TYPE_FAILED: self.CLEAR_TYPE_FAILED,
|
|
|
|
|
self.GAME_CLEAR_TYPE_CLEARED: self.CLEAR_TYPE_CLEARED,
|
|
|
|
|
self.GAME_CLEAR_TYPE_HARD_CLEARED: self.CLEAR_TYPE_HARD_CLEARED,
|
|
|
|
|
self.GAME_CLEAR_TYPE_S_HARD_CLEARED: self.CLEAR_TYPE_S_HARD_CLEARED,
|
|
|
|
|
}[status]
|
|
|
|
|
|
|
|
|
|
def __db_to_game_combo_type(self, db_combo: int) -> int:
|
|
|
|
|
return {
|
|
|
|
|
self.COMBO_TYPE_NONE: self.GAME_COMBO_TYPE_NONE,
|
|
|
|
|
self.COMBO_TYPE_ALMOST_COMBO: self.GAME_COMBO_TYPE_NONE,
|
|
|
|
|
self.COMBO_TYPE_FULL_COMBO: self.GAME_COMBO_TYPE_FULL_COMBO,
|
|
|
|
|
self.COMBO_TYPE_FULL_COMBO_ALL_JUST: self.GAME_COMBO_TYPE_FULL_COMBO_ALL_JUST,
|
|
|
|
|
}[db_combo]
|
|
|
|
|
|
|
|
|
|
def __game_to_db_combo_type(self, game_combo: int, miss_count: int) -> int:
|
|
|
|
|
if game_combo in [
|
|
|
|
|
self.GAME_COMBO_TYPE_NONE,
|
|
|
|
|
self.GAME_COMBO_TYPE_ALL_JUST,
|
|
|
|
|
]:
|
|
|
|
|
if miss_count >= 0 and miss_count <= 2:
|
|
|
|
|
return self.COMBO_TYPE_ALMOST_COMBO
|
|
|
|
|
else:
|
|
|
|
|
return self.COMBO_TYPE_NONE
|
|
|
|
|
if game_combo == self.GAME_COMBO_TYPE_FULL_COMBO:
|
|
|
|
|
return self.COMBO_TYPE_FULL_COMBO
|
|
|
|
|
if game_combo == self.GAME_COMBO_TYPE_FULL_COMBO_ALL_JUST:
|
|
|
|
|
return self.COMBO_TYPE_FULL_COMBO_ALL_JUST
|
2022-10-15 20:56:30 +02:00
|
|
|
|
raise Exception(f"Invalid game_combo value {game_combo}")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
def handle_pcb_rb4error_request(self, request: Node) -> Node:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
return Node.void("pcb")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
def handle_pcb_rb4uptime_update_request(self, request: Node) -> Node:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
return Node.void("pcb")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
def handle_pcb_rb4boot_request(self, request: Node) -> Node:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
shop_id = ID.parse_machine_id(request.child_value("lid"))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
machine = self.get_machine_by_id(shop_id)
|
|
|
|
|
if machine is not None:
|
|
|
|
|
machine_name = machine.name
|
2022-10-15 20:56:30 +02:00
|
|
|
|
close = machine.data.get_bool("close")
|
|
|
|
|
hour = machine.data.get_int("hour")
|
|
|
|
|
minute = machine.data.get_int("minute")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
else:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
machine_name = ""
|
2019-12-08 22:43:49 +01:00
|
|
|
|
close = False
|
|
|
|
|
hour = 0
|
|
|
|
|
minute = 0
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
root = Node.void("pcb")
|
|
|
|
|
sinfo = Node.void("sinfo")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
root.add_child(sinfo)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
sinfo.add_child(Node.string("nm", machine_name))
|
|
|
|
|
sinfo.add_child(Node.bool("cl_enbl", close))
|
|
|
|
|
sinfo.add_child(Node.u8("cl_h", hour))
|
|
|
|
|
sinfo.add_child(Node.u8("cl_m", minute))
|
|
|
|
|
sinfo.add_child(Node.bool("shop_flag", True))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
return root
|
|
|
|
|
|
|
|
|
|
def handle_lobby_rb4entry_request(self, request: Node) -> Node:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
root = Node.void("lobby")
|
|
|
|
|
root.add_child(Node.s32("interval", 120))
|
|
|
|
|
root.add_child(Node.s32("interval_p", 120))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Create a lobby entry for this user
|
2022-10-15 20:56:30 +02:00
|
|
|
|
extid = request.child_value("e/uid")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
userid = self.data.remote.user.from_extid(self.game, self.version, extid)
|
|
|
|
|
if userid is not None:
|
|
|
|
|
profile = self.get_profile(userid)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
info = self.data.local.lobby.get_play_session_info(
|
|
|
|
|
self.game, self.version, userid
|
|
|
|
|
)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
if profile is None or info is None:
|
|
|
|
|
return root
|
|
|
|
|
|
|
|
|
|
self.data.local.lobby.put_lobby(
|
|
|
|
|
self.game,
|
|
|
|
|
self.version,
|
|
|
|
|
userid,
|
|
|
|
|
{
|
2022-10-15 20:56:30 +02:00
|
|
|
|
"mid": request.child_value("e/mid"),
|
|
|
|
|
"ng": request.child_value("e/ng"),
|
|
|
|
|
"mopt": request.child_value("e/mopt"),
|
|
|
|
|
"lid": request.child_value("e/lid"),
|
|
|
|
|
"sn": request.child_value("e/sn"),
|
|
|
|
|
"pref": request.child_value("e/pref"),
|
|
|
|
|
"stg": request.child_value("e/stg"),
|
|
|
|
|
"pside": request.child_value("e/pside"),
|
|
|
|
|
"eatime": request.child_value("e/eatime"),
|
|
|
|
|
"ga": request.child_value("e/ga"),
|
|
|
|
|
"gp": request.child_value("e/gp"),
|
|
|
|
|
"la": request.child_value("e/la"),
|
|
|
|
|
"ver": request.child_value("e/ver"),
|
|
|
|
|
"tension": request.child_value("e/tension"),
|
|
|
|
|
},
|
2019-12-08 22:43:49 +01:00
|
|
|
|
)
|
|
|
|
|
lobby = self.data.local.lobby.get_lobby(
|
|
|
|
|
self.game,
|
|
|
|
|
self.version,
|
|
|
|
|
userid,
|
|
|
|
|
)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
root.add_child(Node.s32("eid", lobby.get_int("id")))
|
|
|
|
|
e = Node.void("e")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
root.add_child(e)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
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.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")))
|
|
|
|
|
e.add_child(Node.s16("mg", profile.get_int("mg")))
|
|
|
|
|
e.add_child(Node.s32("mopt", lobby.get_int("mopt")))
|
|
|
|
|
e.add_child(Node.string("lid", lobby.get_str("lid")))
|
|
|
|
|
e.add_child(Node.string("sn", lobby.get_str("sn")))
|
|
|
|
|
e.add_child(Node.u8("pref", lobby.get_int("pref")))
|
|
|
|
|
e.add_child(Node.s8("stg", lobby.get_int("stg")))
|
|
|
|
|
e.add_child(Node.s8("pside", lobby.get_int("pside")))
|
|
|
|
|
e.add_child(Node.s16("eatime", lobby.get_int("eatime")))
|
|
|
|
|
e.add_child(Node.u8_array("ga", lobby.get_int_array("ga", 4)))
|
|
|
|
|
e.add_child(Node.u16("gp", lobby.get_int("gp")))
|
|
|
|
|
e.add_child(Node.u8_array("la", lobby.get_int_array("la", 4)))
|
|
|
|
|
e.add_child(Node.u8("ver", lobby.get_int("ver")))
|
|
|
|
|
e.add_child(Node.s8("tension", lobby.get_int("tension")))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
return root
|
|
|
|
|
|
|
|
|
|
def handle_lobby_rb4read_request(self, request: Node) -> Node:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
root = Node.void("lobby")
|
|
|
|
|
root.add_child(Node.s32("interval", 120))
|
|
|
|
|
root.add_child(Node.s32("interval_p", 120))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Look up all lobbies matching the criteria specified
|
2022-10-15 20:56:30 +02:00
|
|
|
|
ver = request.child_value("var")
|
|
|
|
|
mg = request.child_value("m_grade") # noqa: F841
|
|
|
|
|
extid = request.child_value("uid")
|
|
|
|
|
limit = request.child_value("max")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
userid = self.data.remote.user.from_extid(self.game, self.version, extid)
|
|
|
|
|
if userid is not None:
|
|
|
|
|
lobbies = self.data.local.lobby.get_all_lobbies(self.game, self.version)
|
2023-02-17 04:02:41 +01:00
|
|
|
|
for user, lobby in lobbies:
|
2019-12-08 22:43:49 +01:00
|
|
|
|
if limit <= 0:
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
if user == userid:
|
|
|
|
|
# If we have our own lobby, don't return it
|
|
|
|
|
continue
|
2022-10-15 20:56:30 +02:00
|
|
|
|
if ver != lobby.get_int("ver"):
|
2019-12-08 22:43:49 +01:00
|
|
|
|
# Don't return lobby data for different versions
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
profile = self.get_profile(user)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
info = self.data.local.lobby.get_play_session_info(
|
|
|
|
|
self.game, self.version, userid
|
|
|
|
|
)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
if profile is None or info is None:
|
|
|
|
|
# No profile info, don't return this lobby
|
|
|
|
|
return root
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
e = Node.void("e")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
root.add_child(e)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
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.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")))
|
|
|
|
|
e.add_child(Node.s16("mg", profile.get_int("mg")))
|
|
|
|
|
e.add_child(Node.s32("mopt", lobby.get_int("mopt")))
|
|
|
|
|
e.add_child(Node.string("lid", lobby.get_str("lid")))
|
|
|
|
|
e.add_child(Node.string("sn", lobby.get_str("sn")))
|
|
|
|
|
e.add_child(Node.u8("pref", lobby.get_int("pref")))
|
|
|
|
|
e.add_child(Node.s8("stg", lobby.get_int("stg")))
|
|
|
|
|
e.add_child(Node.s8("pside", lobby.get_int("pside")))
|
|
|
|
|
e.add_child(Node.s16("eatime", lobby.get_int("eatime")))
|
|
|
|
|
e.add_child(Node.u8_array("ga", lobby.get_int_array("ga", 4)))
|
|
|
|
|
e.add_child(Node.u16("gp", lobby.get_int("gp")))
|
|
|
|
|
e.add_child(Node.u8_array("la", lobby.get_int_array("la", 4)))
|
|
|
|
|
e.add_child(Node.u8("ver", lobby.get_int("ver")))
|
|
|
|
|
e.add_child(Node.s8("tension", lobby.get_int("tension")))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
limit = limit - 1
|
|
|
|
|
|
|
|
|
|
return root
|
|
|
|
|
|
|
|
|
|
def handle_lobby_rb4delete_request(self, request: Node) -> Node:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
eid = request.child_value("eid")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
self.data.local.lobby.destroy_lobby(eid)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
return Node.void("lobby")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
def handle_shop_rb4setting_write_request(self, request: Node) -> Node:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
return Node.void("shop")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
def handle_shop_rb4info_write_request(self, request: Node) -> Node:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
self.update_machine_name(request.child_value("sinfo/nm"))
|
|
|
|
|
self.update_machine_data(
|
|
|
|
|
{
|
|
|
|
|
"close": request.child_value("sinfo/cl_enbl"),
|
|
|
|
|
"hour": request.child_value("sinfo/cl_h"),
|
|
|
|
|
"minute": request.child_value("sinfo/cl_m"),
|
|
|
|
|
"pref": request.child_value("sinfo/prf"),
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
return Node.void("shop")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
def __add_event_info(self, root: Node) -> None:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
event_ctrl = Node.void("event_ctrl")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
root.add_child(event_ctrl)
|
|
|
|
|
# Contains zero or more nodes like:
|
|
|
|
|
# <data>
|
|
|
|
|
# <type __type="s32">any</type>
|
|
|
|
|
# <index __type="s32">any</phase>
|
|
|
|
|
# <value __type="s32">any</phase>
|
|
|
|
|
# <value2 __type="s32">any</phase>
|
|
|
|
|
# <start_time __type="s32">any</phase>
|
|
|
|
|
# <end_time __type="s32">any</phase>
|
|
|
|
|
# </data>
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
item_lock_ctrl = Node.void("item_lock_ctrl")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
root.add_child(item_lock_ctrl)
|
|
|
|
|
# Contains zero or more nodes like:
|
|
|
|
|
# <item>
|
|
|
|
|
# <type __type="u8">any</type>
|
|
|
|
|
# <id __type="u16">any</id>
|
|
|
|
|
# <param __type="u16">0-3</param>
|
|
|
|
|
# </item>
|
|
|
|
|
|
|
|
|
|
def __add_shop_score(self, root: Node) -> None:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
shop_score = Node.void("shop_score")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
root.add_child(shop_score)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
today = Node.void("today")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
shop_score.add_child(today)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
yesterday = Node.void("yesterday")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
shop_score.add_child(yesterday)
|
|
|
|
|
|
|
|
|
|
all_profiles = self.data.local.user.get_all_profiles(self.game, self.version)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
all_attempts = self.data.local.music.get_all_attempts(
|
|
|
|
|
self.game,
|
|
|
|
|
self.version,
|
|
|
|
|
timelimit=(Time.beginning_of_today() - Time.SECONDS_IN_DAY),
|
|
|
|
|
)
|
2021-08-20 06:43:59 +02:00
|
|
|
|
machine = self.data.local.machine.get_machine(self.config.machine.pcbid)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
if machine.arcade is not None:
|
|
|
|
|
lids = [
|
2022-10-15 20:56:30 +02:00
|
|
|
|
machine.id
|
|
|
|
|
for machine in self.data.local.machine.get_all_machines(machine.arcade)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
]
|
|
|
|
|
else:
|
|
|
|
|
lids = [machine.id]
|
|
|
|
|
|
|
|
|
|
relevant_profiles = [
|
2022-10-15 20:56:30 +02:00
|
|
|
|
profile for profile in all_profiles if profile[1].get_int("lid", -1) in lids
|
2019-12-08 22:43:49 +01:00
|
|
|
|
]
|
|
|
|
|
|
2023-02-17 04:02:41 +01:00
|
|
|
|
for rootnode, timeoffset in [
|
2019-12-08 22:43:49 +01:00
|
|
|
|
(today, 0),
|
|
|
|
|
(yesterday, Time.SECONDS_IN_DAY),
|
|
|
|
|
]:
|
|
|
|
|
# Grab all attempts made in the relevant day
|
|
|
|
|
relevant_attempts = [
|
2022-10-15 20:56:30 +02:00
|
|
|
|
attempt
|
|
|
|
|
for attempt in all_attempts
|
2019-12-08 22:43:49 +01:00
|
|
|
|
if (
|
2022-10-15 20:56:30 +02:00
|
|
|
|
attempt[1].timestamp >= (Time.beginning_of_today() - timeoffset)
|
|
|
|
|
and attempt[1].timestamp <= (Time.end_of_today() - timeoffset)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
)
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
# Calculate scores based on attempt
|
|
|
|
|
scores_by_user: Dict[UserID, Dict[int, Dict[int, Attempt]]] = {}
|
2023-02-17 04:02:41 +01:00
|
|
|
|
for userid, attempt in relevant_attempts:
|
2019-12-08 22:43:49 +01:00
|
|
|
|
if userid not in scores_by_user:
|
|
|
|
|
scores_by_user[userid] = {}
|
|
|
|
|
if attempt.id not in scores_by_user[userid]:
|
|
|
|
|
scores_by_user[userid][attempt.id] = {}
|
|
|
|
|
if attempt.chart not in scores_by_user[userid][attempt.id]:
|
|
|
|
|
# No high score for this yet, just use this attempt
|
|
|
|
|
scores_by_user[userid][attempt.id][attempt.chart] = attempt
|
|
|
|
|
else:
|
|
|
|
|
# If this attempt is better than the stored one, replace it
|
2022-10-15 20:56:30 +02:00
|
|
|
|
if (
|
|
|
|
|
scores_by_user[userid][attempt.id][attempt.chart].points
|
|
|
|
|
< attempt.points
|
|
|
|
|
):
|
2019-12-08 22:43:49 +01:00
|
|
|
|
scores_by_user[userid][attempt.id][attempt.chart] = attempt
|
|
|
|
|
|
|
|
|
|
# Calculate points earned by user in the day
|
|
|
|
|
points_by_user: Dict[UserID, int] = {}
|
|
|
|
|
for userid in scores_by_user:
|
|
|
|
|
points_by_user[userid] = 0
|
|
|
|
|
for mid in scores_by_user[userid]:
|
|
|
|
|
for chart in scores_by_user[userid][mid]:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
points_by_user[userid] = (
|
|
|
|
|
points_by_user[userid]
|
|
|
|
|
+ scores_by_user[userid][mid][chart].points
|
|
|
|
|
)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Output that day's earned points
|
2023-02-17 04:02:41 +01:00
|
|
|
|
for userid, profile in relevant_profiles:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
data = Node.void("data")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
rootnode.add_child(data)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
data.add_child(
|
|
|
|
|
Node.s16(
|
|
|
|
|
"day_id", int((Time.now() - timeoffset) / Time.SECONDS_IN_DAY)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
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()))
|
|
|
|
|
data.add_child(Node.string("name", profile.get_str("name")))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
rootnode.add_child(
|
|
|
|
|
Node.s32("timestamp", Time.beginning_of_today() - timeoffset)
|
|
|
|
|
)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
def handle_info_rb4common_request(self, request: Node) -> Node:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
root = Node.void("info")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
self.__add_event_info(root)
|
|
|
|
|
self.__add_shop_score(root)
|
|
|
|
|
|
|
|
|
|
return root
|
|
|
|
|
|
|
|
|
|
def handle_info_rb4ranking_request(self, request: Node) -> Node:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
version = request.child_value("ver")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
root = Node.void("info")
|
|
|
|
|
root.add_child(Node.s32("ver", version))
|
|
|
|
|
ranking = Node.void("ranking")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
root.add_child(ranking)
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
def add_hitchart(
|
|
|
|
|
name: str, start: int, end: int, hitchart: List[Tuple[int, int]]
|
|
|
|
|
) -> None:
|
2019-12-08 22:43:49 +01:00
|
|
|
|
base = Node.void(name)
|
|
|
|
|
ranking.add_child(base)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
base.add_child(Node.s32("bt", start))
|
|
|
|
|
base.add_child(Node.s32("et", end))
|
|
|
|
|
new = Node.void("new")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
base.add_child(new)
|
|
|
|
|
|
2023-02-17 04:02:41 +01:00
|
|
|
|
for mid, plays in hitchart:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
d = Node.void("d")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
new.add_child(d)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
d.add_child(Node.s16("mid", mid))
|
|
|
|
|
d.add_child(Node.s32("cnt", plays))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Weekly hit chart
|
|
|
|
|
add_hitchart(
|
2022-10-15 20:56:30 +02:00
|
|
|
|
"weekly",
|
2019-12-08 22:43:49 +01:00
|
|
|
|
Time.now() - Time.SECONDS_IN_WEEK,
|
|
|
|
|
Time.now(),
|
|
|
|
|
self.data.local.music.get_hit_chart(self.game, self.version, 1024, 7),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Monthly hit chart
|
|
|
|
|
add_hitchart(
|
2022-10-15 20:56:30 +02:00
|
|
|
|
"monthly",
|
2019-12-08 22:43:49 +01:00
|
|
|
|
Time.now() - Time.SECONDS_IN_DAY * 30,
|
|
|
|
|
Time.now(),
|
|
|
|
|
self.data.local.music.get_hit_chart(self.game, self.version, 1024, 30),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# All time hit chart
|
|
|
|
|
add_hitchart(
|
2022-10-15 20:56:30 +02:00
|
|
|
|
"total",
|
2019-12-08 22:43:49 +01:00
|
|
|
|
Time.now() - Time.SECONDS_IN_DAY * 365,
|
|
|
|
|
Time.now(),
|
|
|
|
|
self.data.local.music.get_hit_chart(self.game, self.version, 1024, 365),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return root
|
|
|
|
|
|
|
|
|
|
def handle_info_rb4shop_score_ranking_request(self, request: Node) -> Node:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
start_music_id = request.child_value("min")
|
|
|
|
|
end_music_id = request.child_value("max")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
root = Node.void("info")
|
|
|
|
|
shop_score = Node.void("shop_score")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
root.add_child(shop_score)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
shop_score.add_child(Node.s32("time", Time.now()))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
2021-08-20 06:43:13 +02:00
|
|
|
|
profiles: Dict[UserID, Profile] = {}
|
2019-12-08 22:43:49 +01:00
|
|
|
|
for songid in range(start_music_id, end_music_id + 1):
|
|
|
|
|
allscores = self.data.local.music.get_all_scores(
|
|
|
|
|
self.game,
|
|
|
|
|
self.version,
|
|
|
|
|
songid=songid,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
for ng in [
|
|
|
|
|
self.CHART_TYPE_BASIC,
|
|
|
|
|
self.CHART_TYPE_MEDIUM,
|
|
|
|
|
self.CHART_TYPE_HARD,
|
|
|
|
|
self.CHART_TYPE_SPECIAL,
|
|
|
|
|
]:
|
|
|
|
|
scores = sorted(
|
|
|
|
|
[score for score in allscores if score[1].chart == ng],
|
|
|
|
|
key=lambda score: score[1].points,
|
|
|
|
|
reverse=True,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
for i in range(len(scores)):
|
|
|
|
|
userid, score = scores[i]
|
|
|
|
|
if userid not in profiles:
|
|
|
|
|
profiles[userid] = self.get_any_profile(userid)
|
|
|
|
|
profile = profiles[userid]
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
data = Node.void("data")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
shop_score.add_child(data)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
data.add_child(Node.s32("rank", i + 1))
|
|
|
|
|
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.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))
|
|
|
|
|
data.add_child(Node.string("name", profile.get_str("name")))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
return root
|
|
|
|
|
|
|
|
|
|
def handle_info_rb4pzlcmt_read_request(self, request: Node) -> Node:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
extid = request.child_value("uid")
|
|
|
|
|
locid = ID.parse_machine_id(request.child_value("lid"))
|
|
|
|
|
limit = request.child_value("limit")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
userid = self.data.remote.user.from_extid(self.game, self.version, extid)
|
|
|
|
|
|
|
|
|
|
comments = [
|
2022-10-15 20:56:30 +02:00
|
|
|
|
achievement
|
|
|
|
|
for achievement in self.data.local.user.get_all_time_based_achievements(
|
|
|
|
|
self.game, self.version
|
|
|
|
|
)
|
|
|
|
|
if achievement[1].type == "puzzle_comment"
|
2019-12-08 22:43:49 +01:00
|
|
|
|
]
|
|
|
|
|
comments.sort(key=lambda x: x[1].timestamp, reverse=True)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
favorites = [comment for comment in comments if comment[0] == userid]
|
2019-12-08 22:43:49 +01:00
|
|
|
|
locationcomments = [
|
2022-10-15 20:56:30 +02:00
|
|
|
|
comment for comment in comments if comment[1].data.get_int("locid") == locid
|
2019-12-08 22:43:49 +01:00
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
# Cap all comment blocks to the limit
|
|
|
|
|
if limit >= 0:
|
|
|
|
|
comments = comments[:limit]
|
|
|
|
|
favorites = favorites[:limit]
|
|
|
|
|
locationcomments = locationcomments[:limit]
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
root = Node.void("info")
|
|
|
|
|
comment = Node.void("comment")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
root.add_child(comment)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
comment.add_child(Node.s32("time", Time.now()))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Mapping of profiles to userIDs
|
|
|
|
|
uid_mapping = {
|
|
|
|
|
uid: prof for (uid, prof) in self.get_any_profiles([c[0] for c in comments])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Handle anonymous comments by returning a default profile
|
2021-08-20 06:43:13 +02:00
|
|
|
|
uid_mapping[UserID(0)] = Profile(
|
|
|
|
|
self.game,
|
|
|
|
|
self.version,
|
|
|
|
|
"",
|
|
|
|
|
0,
|
2022-10-15 20:56:30 +02:00
|
|
|
|
{"name": "PLAYER"},
|
2021-08-20 06:43:13 +02:00
|
|
|
|
)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
def add_comments(name: str, selected: List[Tuple[UserID, Achievement]]) -> None:
|
2023-02-17 04:02:41 +01:00
|
|
|
|
for uid, ach in selected:
|
2019-12-08 22:43:49 +01:00
|
|
|
|
cmnt = Node.void(name)
|
|
|
|
|
root.add_child(cmnt)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
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")))
|
|
|
|
|
cmnt.add_child(
|
|
|
|
|
Node.string("lid", ID.format_machine_id(ach.data.get_int("locid")))
|
|
|
|
|
)
|
|
|
|
|
cmnt.add_child(Node.s8("pref", ach.data.get_int("prefecture")))
|
|
|
|
|
cmnt.add_child(Node.s32("time", ach.timestamp))
|
|
|
|
|
cmnt.add_child(Node.string("comment", ach.data.get_str("comment")))
|
|
|
|
|
cmnt.add_child(Node.bool("is_tweet", ach.data.get_bool("tweet")))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Add all comments
|
2022-10-15 20:56:30 +02:00
|
|
|
|
add_comments("c", comments)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Add personal comments (favorites)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
add_comments("cf", favorites)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Add location comments
|
2022-10-15 20:56:30 +02:00
|
|
|
|
add_comments("cs", locationcomments)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
return root
|
|
|
|
|
|
|
|
|
|
def handle_info_rb4pzlcmt_write_request(self, request: Node) -> Node:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
extid = request.child_value("uid")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
userid = self.data.remote.user.from_extid(self.game, self.version, extid)
|
|
|
|
|
if userid is None:
|
|
|
|
|
# Anonymous comment
|
|
|
|
|
userid = UserID(0)
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
icon = request.child_value("icon")
|
|
|
|
|
bln = request.child_value("bln")
|
|
|
|
|
locid = ID.parse_machine_id(request.child_value("lid"))
|
|
|
|
|
prefecture = request.child_value("pref")
|
|
|
|
|
comment = request.child_value("comment")
|
|
|
|
|
is_tweet = request.child_value("is_tweet")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Link comment to user's profile
|
|
|
|
|
self.data.local.user.put_time_based_achievement(
|
|
|
|
|
self.game,
|
|
|
|
|
self.version,
|
|
|
|
|
userid,
|
|
|
|
|
0, # We never have an ID for this, since comments are add-only
|
2022-10-15 20:56:30 +02:00
|
|
|
|
"puzzle_comment",
|
2019-12-08 22:43:49 +01:00
|
|
|
|
{
|
2022-10-15 20:56:30 +02:00
|
|
|
|
"icon": icon,
|
|
|
|
|
"bln": bln,
|
|
|
|
|
"locid": locid,
|
|
|
|
|
"prefecture": prefecture,
|
|
|
|
|
"comment": comment,
|
|
|
|
|
"tweet": is_tweet,
|
2019-12-08 22:43:49 +01:00
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
return Node.void("info")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
def handle_player_rb4start_request(self, request: Node) -> Node:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
root = Node.void("player")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Create a new play session based on info from the request
|
2022-10-15 20:56:30 +02:00
|
|
|
|
refid = request.child_value("rid")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
userid = self.data.remote.user.from_refid(self.game, self.version, refid)
|
|
|
|
|
if userid is not None:
|
|
|
|
|
self.data.local.lobby.put_play_session_info(
|
|
|
|
|
self.game,
|
|
|
|
|
self.version,
|
|
|
|
|
userid,
|
|
|
|
|
{
|
2022-10-15 20:56:30 +02:00
|
|
|
|
"ga": request.child_value("ga"),
|
|
|
|
|
"gp": request.child_value("gp"),
|
|
|
|
|
"la": request.child_value("la"),
|
|
|
|
|
"pnid": request.child_value("pnid"),
|
2019-12-08 22:43:49 +01:00
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
info = self.data.local.lobby.get_play_session_info(
|
|
|
|
|
self.game,
|
|
|
|
|
self.version,
|
|
|
|
|
userid,
|
|
|
|
|
)
|
|
|
|
|
if info is not None:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
play_id = info.get_int("id")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
else:
|
|
|
|
|
play_id = 0
|
|
|
|
|
else:
|
|
|
|
|
play_id = 0
|
|
|
|
|
|
|
|
|
|
# Session stuff, and resend global defaults
|
2022-10-15 20:56:30 +02:00
|
|
|
|
root.add_child(Node.s32("plyid", play_id))
|
|
|
|
|
root.add_child(Node.u64("start_time", Time.now() * 1000))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
self.__add_event_info(root)
|
|
|
|
|
|
|
|
|
|
return root
|
|
|
|
|
|
|
|
|
|
def handle_player_rb4end_request(self, request: Node) -> Node:
|
|
|
|
|
# Destroy play session based on info from the request
|
2022-10-15 20:56:30 +02:00
|
|
|
|
refid = request.child_value("rid")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
userid = self.data.remote.user.from_refid(self.game, self.version, refid)
|
|
|
|
|
if userid is not None:
|
|
|
|
|
# Kill any lingering lobbies by this user
|
|
|
|
|
lobby = self.data.local.lobby.get_lobby(
|
|
|
|
|
self.game,
|
|
|
|
|
self.version,
|
|
|
|
|
userid,
|
|
|
|
|
)
|
|
|
|
|
if lobby is not None:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
self.data.local.lobby.destroy_lobby(lobby.get_int("id"))
|
|
|
|
|
self.data.local.lobby.destroy_play_session_info(
|
|
|
|
|
self.game, self.version, userid
|
|
|
|
|
)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
return Node.void("player")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
def handle_player_rb4readepisode_request(self, request: Node) -> Node:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
extid = request.child_value("user_id")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
userid = self.data.remote.user.from_extid(self.game, self.version, extid)
|
|
|
|
|
if userid is not None:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
achievements = self.data.local.user.get_achievements(
|
|
|
|
|
self.game, self.version, userid
|
|
|
|
|
)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
else:
|
|
|
|
|
achievements = []
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
root = Node.void("player")
|
|
|
|
|
pdata = Node.void("pdata")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
root.add_child(pdata)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
episode = Node.void("episode")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
pdata.add_child(episode)
|
|
|
|
|
|
|
|
|
|
for achievement in achievements:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
if achievement.type != "episode":
|
2019-12-08 22:43:49 +01:00
|
|
|
|
continue
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
info = Node.void("info")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
episode.add_child(info)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
info.add_child(Node.s32("user_id", extid))
|
|
|
|
|
info.add_child(Node.u8("type", achievement.id))
|
|
|
|
|
info.add_child(Node.u16("value0", achievement.data.get_int("value0")))
|
|
|
|
|
info.add_child(Node.u16("value1", achievement.data.get_int("value1")))
|
|
|
|
|
info.add_child(Node.string("text", achievement.data.get_str("text")))
|
|
|
|
|
info.add_child(Node.s32("time", achievement.data.get_int("time")))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
return root
|
|
|
|
|
|
|
|
|
|
def handle_player_rb4readscore_request(self, request: Node) -> Node:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
refid = request.child_value("rid")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
userid = self.data.remote.user.from_refid(self.game, self.version, refid)
|
|
|
|
|
if userid is None:
|
|
|
|
|
scores: List[Score] = []
|
|
|
|
|
else:
|
|
|
|
|
scores = self.data.remote.music.get_scores(self.game, self.version, userid)
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
root = Node.void("player")
|
|
|
|
|
pdata = Node.void("pdata")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
root.add_child(pdata)
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
record = Node.void("record")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
pdata.add_child(record)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
record_old = Node.void("record_old")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
pdata.add_child(record_old)
|
|
|
|
|
|
|
|
|
|
for score in scores:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
rec = Node.void("rec")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
record.add_child(rec)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
rec.add_child(Node.s16("mid", score.id))
|
|
|
|
|
rec.add_child(Node.s8("ntgrd", score.chart))
|
|
|
|
|
rec.add_child(Node.s32("pc", score.plays))
|
|
|
|
|
rec.add_child(
|
|
|
|
|
Node.s8(
|
|
|
|
|
"ct", self.__db_to_game_clear_type(score.data.get_int("clear_type"))
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
rec.add_child(Node.s16("ar", score.data.get_int("achievement_rate")))
|
|
|
|
|
rec.add_child(Node.s16("scr", score.points))
|
|
|
|
|
rec.add_child(Node.s16("ms", score.data.get_int("miss_count")))
|
|
|
|
|
rec.add_child(
|
|
|
|
|
Node.s16(
|
|
|
|
|
"param",
|
|
|
|
|
self.__db_to_game_combo_type(score.data.get_int("combo_type"))
|
|
|
|
|
+ score.data.get_int("param"),
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
rec.add_child(Node.s32("bscrt", score.timestamp))
|
|
|
|
|
rec.add_child(
|
|
|
|
|
Node.s32("bart", score.data.get_int("best_achievement_rate_time"))
|
|
|
|
|
)
|
|
|
|
|
rec.add_child(Node.s32("bctt", score.data.get_int("best_clear_type_time")))
|
|
|
|
|
rec.add_child(Node.s32("bmst", score.data.get_int("best_miss_count_time")))
|
|
|
|
|
rec.add_child(Node.s32("time", score.data.get_int("last_played_time")))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
return root
|
|
|
|
|
|
|
|
|
|
def handle_player_rb4selectscore_request(self, request: Node) -> Node:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
extid = request.child_value("uid")
|
|
|
|
|
songid = request.child_value("music_id")
|
|
|
|
|
chart = request.child_value("note_grade")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
userid = self.data.remote.user.from_extid(self.game, self.version, extid)
|
|
|
|
|
if userid is None:
|
|
|
|
|
score = None
|
|
|
|
|
profile = None
|
|
|
|
|
else:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
score = self.data.remote.music.get_score(
|
|
|
|
|
self.game, self.version, userid, songid, chart
|
|
|
|
|
)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
profile = self.get_any_profile(userid)
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
root = Node.void("player")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
if score is not None and profile is not None:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
player_select_score = Node.void("player_select_score")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
root.add_child(player_select_score)
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
player_select_score.add_child(Node.s32("user_id", extid))
|
|
|
|
|
player_select_score.add_child(Node.string("name", profile.get_str("name")))
|
|
|
|
|
player_select_score.add_child(Node.s32("m_score", score.points))
|
|
|
|
|
player_select_score.add_child(Node.s32("m_scoreTime", score.timestamp))
|
|
|
|
|
player_select_score.add_child(
|
|
|
|
|
Node.s16("m_iconID", profile.get_dict("config").get_int("icon_id"))
|
|
|
|
|
)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
return root
|
|
|
|
|
|
|
|
|
|
def handle_player_rbsvLinkageSave_request(self, request: Node) -> Node:
|
|
|
|
|
# I think this is ReflecBeat/SoundVoltex linkage save, and I
|
|
|
|
|
# am somewhat convinced that PK/BN is for packets/blocks, but
|
|
|
|
|
# whatever.
|
2022-10-15 20:56:30 +02:00
|
|
|
|
root = Node.void("player")
|
|
|
|
|
root.add_child(Node.s32("before_pk_value", -1))
|
|
|
|
|
root.add_child(Node.s32("after_pk_value", -1))
|
|
|
|
|
root.add_child(Node.s32("before_bn_value", -1))
|
|
|
|
|
root.add_child(Node.s32("after_bn_value", -1))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
return root
|
|
|
|
|
|
|
|
|
|
def handle_player_rb4total_bestallrank_read_request(self, request: Node) -> Node:
|
|
|
|
|
# This gives us a 6-integer array mapping to user scores for the following:
|
|
|
|
|
# [total score, basic chart score, medium chart score, hard chart score,
|
|
|
|
|
# special chart score, new songs score].
|
|
|
|
|
# It appears to return several 6-array values similar to the following:
|
|
|
|
|
# <score>
|
|
|
|
|
# <rank __type="s32" __count="6">1 2 3 4 5 6</rank>
|
|
|
|
|
# <score __type="s32" __count="6">101 102 103 104 105 106</score>
|
|
|
|
|
# <allrank __type="s32" __count="6">7 8 9 10 11 12</allrank>
|
|
|
|
|
# </score>
|
|
|
|
|
# The first 'rank' is the displayed value for the six categories. The
|
|
|
|
|
# second and third values appear unused in-game. I think this is supposed
|
|
|
|
|
# to give a player the idea of what ranking they are on the server for
|
|
|
|
|
# various scores.
|
2022-10-15 20:56:30 +02:00
|
|
|
|
current_scores = request.child_value("score")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# First, grab all scores on the network for this version, and all songs
|
|
|
|
|
# available so we know which songs are new to this version of the game.
|
|
|
|
|
all_scores = self.data.remote.music.get_all_scores(self.game, self.version)
|
|
|
|
|
all_songs = self.data.local.music.get_all_songs(self.game, self.version)
|
|
|
|
|
|
|
|
|
|
# Figure out what song IDs are new
|
2022-10-15 20:56:30 +02:00
|
|
|
|
new_songs = {
|
|
|
|
|
song.id
|
|
|
|
|
for song in all_songs
|
|
|
|
|
if song.data.get_int("folder", 0) == self.version
|
|
|
|
|
}
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Now grab all participating users that had scores
|
|
|
|
|
all_users = {userid for (userid, score) in all_scores}
|
|
|
|
|
|
|
|
|
|
# Now, group the scores by user, so we can add up the totals, only including
|
|
|
|
|
# scores where the user at least cleared the song.
|
|
|
|
|
scores_by_user = {
|
|
|
|
|
userid: [
|
2022-10-15 20:56:30 +02:00
|
|
|
|
score
|
|
|
|
|
for (uid, score) in all_scores
|
|
|
|
|
if uid == userid
|
|
|
|
|
and score.data.get_int("clear_type") >= self.CLEAR_TYPE_CLEARED
|
|
|
|
|
]
|
2019-12-08 22:43:49 +01:00
|
|
|
|
for userid in all_users
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Now, sum up the scores into the six categories that the game expects.
|
|
|
|
|
total_scores = sorted(
|
|
|
|
|
[
|
|
|
|
|
sum([score.points for score in scores])
|
|
|
|
|
for userid, scores in scores_by_user.items()
|
|
|
|
|
],
|
|
|
|
|
reverse=True,
|
|
|
|
|
)
|
|
|
|
|
basic_scores = sorted(
|
|
|
|
|
[
|
2022-10-15 20:56:30 +02:00
|
|
|
|
sum(
|
|
|
|
|
[
|
|
|
|
|
score.points
|
|
|
|
|
for score in scores
|
|
|
|
|
if score.chart == self.CHART_TYPE_BASIC
|
|
|
|
|
]
|
|
|
|
|
)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
for userid, scores in scores_by_user.items()
|
|
|
|
|
],
|
|
|
|
|
reverse=True,
|
|
|
|
|
)
|
|
|
|
|
medium_scores = sorted(
|
|
|
|
|
[
|
2022-10-15 20:56:30 +02:00
|
|
|
|
sum(
|
|
|
|
|
[
|
|
|
|
|
score.points
|
|
|
|
|
for score in scores
|
|
|
|
|
if score.chart == self.CHART_TYPE_MEDIUM
|
|
|
|
|
]
|
|
|
|
|
)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
for userid, scores in scores_by_user.items()
|
|
|
|
|
],
|
|
|
|
|
reverse=True,
|
|
|
|
|
)
|
|
|
|
|
hard_scores = sorted(
|
|
|
|
|
[
|
2022-10-15 20:56:30 +02:00
|
|
|
|
sum(
|
|
|
|
|
[
|
|
|
|
|
score.points
|
|
|
|
|
for score in scores
|
|
|
|
|
if score.chart == self.CHART_TYPE_HARD
|
|
|
|
|
]
|
|
|
|
|
)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
for userid, scores in scores_by_user.items()
|
|
|
|
|
],
|
|
|
|
|
reverse=True,
|
|
|
|
|
)
|
|
|
|
|
special_scores = sorted(
|
|
|
|
|
[
|
2022-10-15 20:56:30 +02:00
|
|
|
|
sum(
|
|
|
|
|
[
|
|
|
|
|
score.points
|
|
|
|
|
for score in scores
|
|
|
|
|
if score.chart == self.CHART_TYPE_SPECIAL
|
|
|
|
|
]
|
|
|
|
|
)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
for userid, scores in scores_by_user.items()
|
|
|
|
|
],
|
|
|
|
|
reverse=True,
|
|
|
|
|
)
|
|
|
|
|
new_scores = sorted(
|
|
|
|
|
[
|
|
|
|
|
sum([score.points for score in scores if score.id in new_songs])
|
|
|
|
|
for userid, scores in scores_by_user.items()
|
|
|
|
|
],
|
|
|
|
|
reverse=True,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Guarantee that a zero score is at the end of every list, so that it makes
|
|
|
|
|
# the algorithm for figuring out place have no edge case.
|
|
|
|
|
total_scores.append(0)
|
|
|
|
|
basic_scores.append(0)
|
|
|
|
|
medium_scores.append(0)
|
|
|
|
|
hard_scores.append(0)
|
|
|
|
|
special_scores.append(0)
|
|
|
|
|
new_scores.append(0)
|
|
|
|
|
|
|
|
|
|
# Now, figure out where we fit based on the scores sent from the game.
|
|
|
|
|
user_place = [1, 1, 1, 1, 1, 1]
|
|
|
|
|
which_score = [
|
|
|
|
|
total_scores,
|
|
|
|
|
basic_scores,
|
|
|
|
|
medium_scores,
|
|
|
|
|
hard_scores,
|
|
|
|
|
special_scores,
|
|
|
|
|
new_scores,
|
|
|
|
|
]
|
|
|
|
|
for i in range(len(user_place)):
|
|
|
|
|
current_score = current_scores[i]
|
|
|
|
|
scores = which_score[i]
|
|
|
|
|
for score in scores:
|
|
|
|
|
if current_score >= score:
|
|
|
|
|
break
|
|
|
|
|
user_place[i] = user_place[i] + 1
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
root = Node.void("player")
|
|
|
|
|
scorenode = Node.void("score")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
root.add_child(scorenode)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
scorenode.add_child(Node.s32_array("rank", user_place))
|
|
|
|
|
scorenode.add_child(Node.s32_array("score", [0] * 6))
|
|
|
|
|
scorenode.add_child(Node.s32_array("allrank", [len(total_scores)] * 6))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
return root
|
|
|
|
|
|
|
|
|
|
def handle_player_rb4delete_request(self, request: Node) -> Node:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
return Node.void("player")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
def handle_player_rb4read_request(self, request: Node) -> Node:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
refid = request.child_value("rid")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
profile = self.get_profile_by_refid(refid)
|
|
|
|
|
if profile:
|
|
|
|
|
return profile
|
2022-10-15 20:56:30 +02:00
|
|
|
|
return Node.void("player")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
def handle_player_rb4succeed_request(self, request: Node) -> Node:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
refid = request.child_value("rid")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
userid = self.data.remote.user.from_refid(self.game, self.version, refid)
|
|
|
|
|
if userid is not None:
|
|
|
|
|
previous_version = self.previous_version()
|
|
|
|
|
profile = previous_version.get_profile(userid)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
achievements = self.data.local.user.get_achievements(
|
|
|
|
|
previous_version.game, previous_version.version, userid
|
|
|
|
|
)
|
|
|
|
|
scores = self.data.remote.music.get_scores(
|
|
|
|
|
previous_version.game, previous_version.version, userid
|
|
|
|
|
)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
else:
|
|
|
|
|
profile = None
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
root = Node.void("player")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
if profile is None:
|
|
|
|
|
# Return empty succeed to say this is new
|
2022-10-15 20:56:30 +02:00
|
|
|
|
root.add_child(Node.string("name", ""))
|
|
|
|
|
root.add_child(Node.s16("lv", -1))
|
|
|
|
|
root.add_child(Node.s32("exp", -1))
|
|
|
|
|
root.add_child(Node.s32("grd", -1))
|
|
|
|
|
root.add_child(Node.s32("ap", -1))
|
|
|
|
|
root.add_child(Node.s32("money", -1))
|
|
|
|
|
root.add_child(Node.void("released"))
|
|
|
|
|
root.add_child(Node.void("mrecord"))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
else:
|
|
|
|
|
# Return previous profile formatted to say this is data succession
|
2022-10-15 20:56:30 +02:00
|
|
|
|
root.add_child(Node.string("name", profile.get_str("name")))
|
|
|
|
|
root.add_child(Node.s16("lv", profile.get_int("lvl")))
|
|
|
|
|
root.add_child(Node.s32("exp", profile.get_int("exp")))
|
|
|
|
|
root.add_child(Node.s32("grd", profile.get_int("mg"))) # This is a guess
|
|
|
|
|
root.add_child(Node.s32("ap", profile.get_int("ap")))
|
|
|
|
|
root.add_child(Node.s32("money", 0))
|
|
|
|
|
|
|
|
|
|
released = Node.void("released")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
root.add_child(released)
|
|
|
|
|
for item in achievements:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
if item.type != "item_0":
|
2019-12-08 22:43:49 +01:00
|
|
|
|
continue
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
released.add_child(Node.s16("i", item.id))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
mrecord = Node.void("mrecord")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
root.add_child(mrecord)
|
|
|
|
|
for score in scores:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
mrec = Node.void("mrec")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
mrecord.add_child(mrec)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
mrec.add_child(Node.s16("mid", score.id))
|
|
|
|
|
mrec.add_child(Node.s8("ntgrd", score.chart))
|
|
|
|
|
mrec.add_child(Node.s32("pc", score.plays))
|
|
|
|
|
mrec.add_child(
|
|
|
|
|
Node.s8(
|
|
|
|
|
"ct",
|
|
|
|
|
self.__db_to_game_clear_type(score.data.get_int("clear_type")),
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
mrec.add_child(Node.s16("ar", score.data.get_int("achievement_rate")))
|
|
|
|
|
mrec.add_child(Node.s16("scr", score.points))
|
|
|
|
|
mrec.add_child(Node.s16("ms", score.data.get_int("miss_count")))
|
|
|
|
|
mrec.add_child(Node.u16("ver", 0))
|
|
|
|
|
mrec.add_child(Node.s32("bst", score.timestamp))
|
|
|
|
|
mrec.add_child(
|
|
|
|
|
Node.s32("bat", score.data.get_int("best_achievement_rate_time"))
|
|
|
|
|
)
|
|
|
|
|
mrec.add_child(
|
|
|
|
|
Node.s32("bct", score.data.get_int("best_clear_type_time"))
|
|
|
|
|
)
|
|
|
|
|
mrec.add_child(
|
|
|
|
|
Node.s32("bmt", score.data.get_int("best_miss_count_time"))
|
|
|
|
|
)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
return root
|
|
|
|
|
|
|
|
|
|
def handle_player_rb4write_request(self, request: Node) -> Node:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
refid = request.child_value("pdata/account/rid")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
profile = self.put_profile_by_refid(refid, request)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
root = Node.void("player")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
if profile is None:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
root.add_child(Node.s32("uid", 0))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
else:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
root.add_child(Node.s32("uid", profile.extid))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
return root
|
|
|
|
|
|
2021-08-20 06:43:13 +02:00
|
|
|
|
def format_profile(self, userid: UserID, profile: Profile) -> Node:
|
2019-12-08 22:43:49 +01:00
|
|
|
|
statistics = self.get_play_statistics(userid)
|
|
|
|
|
game_config = self.get_game_config()
|
2022-10-15 20:56:30 +02:00
|
|
|
|
achievements = self.data.local.user.get_achievements(
|
|
|
|
|
self.game, self.version, userid
|
|
|
|
|
)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
links = self.data.local.user.get_links(self.game, self.version, userid)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
root = Node.void("player")
|
|
|
|
|
pdata = Node.void("pdata")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
root.add_child(pdata)
|
|
|
|
|
|
|
|
|
|
# Account info
|
2022-10-15 20:56:30 +02:00
|
|
|
|
account = Node.void("account")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
pdata.add_child(account)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
account.add_child(Node.s32("usrid", profile.extid))
|
|
|
|
|
account.add_child(Node.s32("tpc", statistics.total_plays))
|
|
|
|
|
account.add_child(Node.s32("dpc", statistics.today_plays))
|
|
|
|
|
account.add_child(Node.s32("crd", 1))
|
|
|
|
|
account.add_child(Node.s32("brd", 1))
|
|
|
|
|
account.add_child(Node.s32("tdc", statistics.total_days))
|
|
|
|
|
account.add_child(Node.s32("intrvld", 0))
|
|
|
|
|
account.add_child(Node.s16("ver", 1))
|
|
|
|
|
account.add_child(Node.u64("pst", 0))
|
|
|
|
|
account.add_child(Node.u64("st", Time.now() * 1000))
|
|
|
|
|
account.add_child(Node.u8("debutVer", 2))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Base profile info
|
2022-10-15 20:56:30 +02:00
|
|
|
|
base = Node.void("base")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
pdata.add_child(base)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
base.add_child(Node.string("name", profile.get_str("name")))
|
|
|
|
|
base.add_child(Node.s32("exp", profile.get_int("exp")))
|
|
|
|
|
base.add_child(Node.s32("lv", profile.get_int("lvl")))
|
|
|
|
|
base.add_child(Node.s32("mg", profile.get_int("mg")))
|
|
|
|
|
base.add_child(Node.s32("ap", profile.get_int("ap")))
|
|
|
|
|
base.add_child(Node.string("cmnt", ""))
|
|
|
|
|
base.add_child(Node.s32("uattr", profile.get_int("uattr")))
|
|
|
|
|
base.add_child(Node.s32("money", profile.get_int("money")))
|
|
|
|
|
base.add_child(Node.s32("tbs", -1))
|
|
|
|
|
base.add_child(Node.s32("tbs_r", -1))
|
|
|
|
|
base.add_child(Node.s32("tbgs", -1))
|
|
|
|
|
base.add_child(Node.s32("tbgs_r", -1))
|
|
|
|
|
base.add_child(Node.s32("tbms", -1))
|
|
|
|
|
base.add_child(Node.s32("tbms_r", -1))
|
|
|
|
|
base.add_child(Node.s32("qe_win", -1))
|
|
|
|
|
base.add_child(Node.s32("qe_legend", -1))
|
|
|
|
|
base.add_child(Node.s32("qe2_win", -1))
|
|
|
|
|
base.add_child(Node.s32("qe2_legend", -1))
|
|
|
|
|
base.add_child(Node.s32("qe3_win", -1))
|
|
|
|
|
base.add_child(Node.s32("qe3_legend", -1))
|
|
|
|
|
base.add_child(Node.s16_array("mlog", [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1]))
|
|
|
|
|
base.add_child(Node.s32("class", profile.get_int("class")))
|
|
|
|
|
base.add_child(Node.s32("class_ar", profile.get_int("class_ar")))
|
|
|
|
|
base.add_child(Node.s32("getrfl", -1))
|
|
|
|
|
base.add_child(Node.s32("upper_pt", profile.get_int("upper_pt")))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Rivals
|
2022-10-15 20:56:30 +02:00
|
|
|
|
rival = Node.void("rival")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
pdata.add_child(rival)
|
|
|
|
|
slotid = 0
|
|
|
|
|
for link in links:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
if link.type != "rival":
|
2019-12-08 22:43:49 +01:00
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
rprofile = self.get_profile(link.other_userid)
|
|
|
|
|
if rprofile is None:
|
|
|
|
|
continue
|
2022-10-15 20:56:30 +02:00
|
|
|
|
lobbyinfo = self.data.local.lobby.get_play_session_info(
|
|
|
|
|
self.game, self.version, link.other_userid
|
|
|
|
|
)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
if lobbyinfo is None:
|
|
|
|
|
lobbyinfo = ValidatedDict()
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
r = Node.void("r")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
rival.add_child(r)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
r.add_child(Node.s32("slot_id", slotid))
|
|
|
|
|
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")))
|
|
|
|
|
r.add_child(Node.s32("class", profile.get_int("class")))
|
|
|
|
|
r.add_child(Node.s32("class_ar", profile.get_int("class_ar")))
|
|
|
|
|
r.add_child(Node.bool("friend", True))
|
|
|
|
|
r.add_child(Node.bool("target", False))
|
|
|
|
|
r.add_child(Node.u32("time", lobbyinfo.get_int("time")))
|
|
|
|
|
r.add_child(Node.u8_array("ga", lobbyinfo.get_int_array("ga", 4)))
|
|
|
|
|
r.add_child(Node.u16("gp", lobbyinfo.get_int("gp")))
|
|
|
|
|
r.add_child(Node.u8_array("ipn", lobbyinfo.get_int_array("la", 4)))
|
|
|
|
|
r.add_child(Node.u8_array("pnid", lobbyinfo.get_int_array("pnid", 16)))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
slotid = slotid + 1
|
|
|
|
|
|
|
|
|
|
# Stamps
|
2022-10-15 20:56:30 +02:00
|
|
|
|
stamp = Node.void("stamp")
|
|
|
|
|
stampdict = profile.get_dict("stamp")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
pdata.add_child(stamp)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
stamp.add_child(
|
|
|
|
|
Node.s32_array("stmpcnt", stampdict.get_int_array("stmpcnt", 10))
|
|
|
|
|
)
|
|
|
|
|
stamp.add_child(Node.s64("area", stampdict.get_int("area")))
|
|
|
|
|
stamp.add_child(Node.s64("prfvst", stampdict.get_int("prfvst")))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Configuration
|
2022-10-15 20:56:30 +02:00
|
|
|
|
configdict = profile.get_dict("config")
|
|
|
|
|
config = Node.void("config")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
pdata.add_child(config)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
config.add_child(Node.u8("msel_bgm", configdict.get_int("msel_bgm")))
|
|
|
|
|
config.add_child(
|
|
|
|
|
Node.u8("narrowdown_type", configdict.get_int("narrowdown_type"))
|
|
|
|
|
)
|
|
|
|
|
config.add_child(Node.s16("icon_id", configdict.get_int("icon_id")))
|
|
|
|
|
config.add_child(Node.s16("byword_0", configdict.get_int("byword_0")))
|
|
|
|
|
config.add_child(Node.s16("byword_1", configdict.get_int("byword_1")))
|
|
|
|
|
config.add_child(
|
|
|
|
|
Node.bool("is_auto_byword_0", configdict.get_bool("is_auto_byword_0"))
|
|
|
|
|
)
|
|
|
|
|
config.add_child(
|
|
|
|
|
Node.bool("is_auto_byword_1", configdict.get_bool("is_auto_byword_1"))
|
|
|
|
|
)
|
|
|
|
|
config.add_child(Node.u8("mrec_type", configdict.get_int("mrec_type")))
|
|
|
|
|
config.add_child(Node.u8("tab_sel", configdict.get_int("tab_sel")))
|
|
|
|
|
config.add_child(Node.u8("card_disp", configdict.get_int("card_disp")))
|
|
|
|
|
config.add_child(
|
|
|
|
|
Node.u8("score_tab_disp", configdict.get_int("score_tab_disp"))
|
|
|
|
|
)
|
|
|
|
|
config.add_child(
|
|
|
|
|
Node.s16("last_music_id", configdict.get_int("last_music_id", -1))
|
|
|
|
|
)
|
|
|
|
|
config.add_child(
|
|
|
|
|
Node.u8("last_note_grade", configdict.get_int("last_note_grade"))
|
|
|
|
|
)
|
|
|
|
|
config.add_child(Node.u8("sort_type", configdict.get_int("sort_type")))
|
|
|
|
|
config.add_child(
|
|
|
|
|
Node.u8("rival_panel_type", configdict.get_int("rival_panel_type"))
|
|
|
|
|
)
|
|
|
|
|
config.add_child(
|
|
|
|
|
Node.u64("random_entry_work", configdict.get_int("random_entry_work"))
|
|
|
|
|
)
|
|
|
|
|
config.add_child(
|
|
|
|
|
Node.u64("custom_folder_work", configdict.get_int("custom_folder_work"))
|
|
|
|
|
)
|
|
|
|
|
config.add_child(Node.u8("folder_type", configdict.get_int("folder_type")))
|
|
|
|
|
config.add_child(
|
|
|
|
|
Node.u8("folder_lamp_type", configdict.get_int("folder_lamp_type"))
|
|
|
|
|
)
|
|
|
|
|
config.add_child(Node.bool("is_tweet", configdict.get_bool("is_tweet")))
|
|
|
|
|
config.add_child(
|
|
|
|
|
Node.bool("is_link_twitter", configdict.get_bool("is_link_twitter"))
|
|
|
|
|
)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Customizations
|
2022-10-15 20:56:30 +02:00
|
|
|
|
customdict = profile.get_dict("custom")
|
|
|
|
|
custom = Node.void("custom")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
pdata.add_child(custom)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
custom.add_child(Node.u8("st_shot", customdict.get_int("st_shot")))
|
|
|
|
|
custom.add_child(Node.u8("st_frame", customdict.get_int("st_frame")))
|
|
|
|
|
custom.add_child(Node.u8("st_expl", customdict.get_int("st_expl")))
|
|
|
|
|
custom.add_child(Node.u8("st_bg", customdict.get_int("st_bg")))
|
|
|
|
|
custom.add_child(Node.u8("st_shot_vol", customdict.get_int("st_shot_vol")))
|
|
|
|
|
custom.add_child(Node.u8("st_bg_bri", customdict.get_int("st_bg_bri")))
|
|
|
|
|
custom.add_child(Node.u8("st_obj_size", customdict.get_int("st_obj_size")))
|
|
|
|
|
custom.add_child(Node.u8("st_jr_gauge", customdict.get_int("st_jr_gauge")))
|
|
|
|
|
custom.add_child(Node.u8("st_clr_gauge", customdict.get_int("st_clr_gauge")))
|
|
|
|
|
custom.add_child(Node.u8("st_jdg_disp", customdict.get_int("st_jdg_disp")))
|
|
|
|
|
custom.add_child(Node.u8("st_tm_disp", customdict.get_int("st_tm_disp")))
|
|
|
|
|
custom.add_child(Node.u8("st_rnd", customdict.get_int("st_rnd")))
|
|
|
|
|
custom.add_child(Node.u8("st_hazard", customdict.get_int("st_hazard")))
|
|
|
|
|
custom.add_child(Node.u8("st_clr_cond", customdict.get_int("st_clr_cond")))
|
|
|
|
|
custom.add_child(
|
|
|
|
|
Node.s16_array("schat_0", customdict.get_int_array("schat_0", 10))
|
|
|
|
|
)
|
|
|
|
|
custom.add_child(
|
|
|
|
|
Node.s16_array("schat_1", customdict.get_int_array("schat_1", 10))
|
|
|
|
|
)
|
|
|
|
|
custom.add_child(Node.u8("cheer_voice", customdict.get_int("cheer_voice")))
|
|
|
|
|
custom.add_child(
|
|
|
|
|
Node.u8("same_time_note_disp", customdict.get_int("same_time_note_disp"))
|
|
|
|
|
)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Unlocks
|
2022-10-15 20:56:30 +02:00
|
|
|
|
released = Node.void("released")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
pdata.add_child(released)
|
|
|
|
|
|
|
|
|
|
for item in achievements:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
if item.type[:5] != "item_":
|
2019-12-08 22:43:49 +01:00
|
|
|
|
continue
|
|
|
|
|
itemtype = int(item.type[5:])
|
2022-10-15 20:56:30 +02:00
|
|
|
|
if game_config.get_bool("force_unlock_songs") and itemtype == 0:
|
2019-12-08 22:43:49 +01:00
|
|
|
|
# Don't echo unlocks when we're force unlocking, we'll do it later
|
|
|
|
|
continue
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
info = Node.void("info")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
released.add_child(info)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
info.add_child(Node.u8("type", itemtype))
|
|
|
|
|
info.add_child(Node.u16("id", item.id))
|
|
|
|
|
info.add_child(Node.u16("param", item.data.get_int("param")))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
if game_config.get_bool("force_unlock_songs"):
|
2019-12-08 22:43:49 +01:00
|
|
|
|
ids: Dict[int, int] = {}
|
|
|
|
|
songs = self.data.local.music.get_all_songs(self.game, self.version)
|
|
|
|
|
for song in songs:
|
|
|
|
|
if song.id not in ids:
|
|
|
|
|
ids[song.id] = 0
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
if song.data.get_int("difficulty") > 0:
|
2019-12-08 22:43:49 +01:00
|
|
|
|
ids[song.id] = ids[song.id] | (1 << song.chart)
|
|
|
|
|
|
|
|
|
|
for songid in ids:
|
|
|
|
|
if ids[songid] == 0:
|
|
|
|
|
continue
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
info = Node.void("info")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
released.add_child(info)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
info.add_child(Node.u8("type", 0))
|
|
|
|
|
info.add_child(Node.u16("id", songid))
|
|
|
|
|
info.add_child(Node.u16("param", ids[songid]))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Announcements
|
2022-10-15 20:56:30 +02:00
|
|
|
|
announce = Node.void("announce")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
pdata.add_child(announce)
|
|
|
|
|
|
|
|
|
|
for announcement in achievements:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
if announcement.type[:13] != "announcement_":
|
2019-12-08 22:43:49 +01:00
|
|
|
|
continue
|
|
|
|
|
announcementtype = int(announcement.type[13:])
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
info = Node.void("info")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
announce.add_child(info)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
info.add_child(Node.u8("type", announcementtype))
|
|
|
|
|
info.add_child(Node.u16("id", announcement.id))
|
|
|
|
|
info.add_child(Node.u16("param", announcement.data.get_int("param")))
|
|
|
|
|
info.add_child(
|
|
|
|
|
Node.bool("bneedannounce", announcement.data.get_bool("need"))
|
|
|
|
|
)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Dojo ranking return
|
2022-10-15 20:56:30 +02:00
|
|
|
|
dojo = Node.void("dojo")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
pdata.add_child(dojo)
|
|
|
|
|
|
|
|
|
|
for entry in achievements:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
if entry.type != "dojo":
|
2019-12-08 22:43:49 +01:00
|
|
|
|
continue
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
rec = Node.void("rec")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
dojo.add_child(rec)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
rec.add_child(Node.s32("class", entry.id))
|
|
|
|
|
rec.add_child(Node.s32("clear_type", entry.data.get_int("clear_type")))
|
|
|
|
|
rec.add_child(Node.s32("total_ar", entry.data.get_int("ar")))
|
|
|
|
|
rec.add_child(Node.s32("total_score", entry.data.get_int("score")))
|
|
|
|
|
rec.add_child(Node.s32("play_count", entry.data.get_int("plays")))
|
|
|
|
|
rec.add_child(
|
|
|
|
|
Node.s32("last_play_time", entry.data.get_int("play_timestamp"))
|
|
|
|
|
)
|
|
|
|
|
rec.add_child(
|
|
|
|
|
Node.s32("record_update_time", entry.data.get_int("record_timestamp"))
|
|
|
|
|
)
|
|
|
|
|
rec.add_child(Node.s32("rank", 0))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Player Parameters
|
2022-10-15 20:56:30 +02:00
|
|
|
|
player_param = Node.void("player_param")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
pdata.add_child(player_param)
|
|
|
|
|
|
|
|
|
|
for param in achievements:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
if param.type[:13] != "player_param_":
|
2019-12-08 22:43:49 +01:00
|
|
|
|
continue
|
|
|
|
|
itemtype = int(param.type[13:])
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
itemnode = Node.void("item")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
player_param.add_child(itemnode)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
itemnode.add_child(Node.s32("type", itemtype))
|
|
|
|
|
itemnode.add_child(Node.s32("bank", param.id))
|
|
|
|
|
itemnode.add_child(
|
|
|
|
|
Node.s32_array("data", param.data.get_int_array("data", 256))
|
|
|
|
|
)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Shop score for players
|
|
|
|
|
self.__add_shop_score(pdata)
|
|
|
|
|
|
|
|
|
|
# Quest data
|
2022-10-15 20:56:30 +02:00
|
|
|
|
questdict = profile.get_dict("quest")
|
|
|
|
|
quest = Node.void("quest")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
pdata.add_child(quest)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
quest.add_child(Node.s16("eye_color", questdict.get_int("eye_color")))
|
|
|
|
|
quest.add_child(Node.s16("body_color", questdict.get_int("body_color")))
|
|
|
|
|
quest.add_child(Node.s16("item", questdict.get_int("item")))
|
|
|
|
|
quest.add_child(Node.string("comment", ""))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Derby settings
|
2022-10-15 20:56:30 +02:00
|
|
|
|
derby = Node.void("derby")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
pdata.add_child(derby)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
derby.add_child(Node.bool("is_open", False))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Codebreaking stuff
|
2022-10-15 20:56:30 +02:00
|
|
|
|
codebreaking = Node.void("codebreaking")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
pdata.add_child(codebreaking)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
codebreaking.add_child(Node.s32("cb_id", -1))
|
|
|
|
|
codebreaking.add_child(Node.s32("cb_sub_id", -1))
|
|
|
|
|
codebreaking.add_child(Node.s32("music_id", -1))
|
|
|
|
|
codebreaking.add_child(Node.string("question", ""))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Unknown IIDX link crap
|
2022-10-15 20:56:30 +02:00
|
|
|
|
iidx_linkage = Node.void("iidx_linkage")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
pdata.add_child(iidx_linkage)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
iidx_linkage.add_child(Node.s32("linkage_id", -1))
|
|
|
|
|
iidx_linkage.add_child(Node.s32("phase", -1))
|
|
|
|
|
iidx_linkage.add_child(Node.s64("long_bit_0", -1))
|
|
|
|
|
iidx_linkage.add_child(Node.s64("long_bit_1", -1))
|
|
|
|
|
iidx_linkage.add_child(Node.s64("long_bit_2", -1))
|
|
|
|
|
iidx_linkage.add_child(Node.s64("long_bit_3", -1))
|
|
|
|
|
iidx_linkage.add_child(Node.s64("long_bit_4", -1))
|
|
|
|
|
iidx_linkage.add_child(Node.s64("long_bit_5", -1))
|
|
|
|
|
iidx_linkage.add_child(Node.s32("add_0", -1))
|
|
|
|
|
iidx_linkage.add_child(Node.s32("add_1", -1))
|
|
|
|
|
iidx_linkage.add_child(Node.s32("add_2", -1))
|
|
|
|
|
iidx_linkage.add_child(Node.s32("add_3", -1))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Unknown event crap
|
2022-10-15 20:56:30 +02:00
|
|
|
|
pue = Node.void("pue")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
pdata.add_child(pue)
|
2022-10-15 20:56:30 +02:00
|
|
|
|
pue.add_child(Node.s32("event_id", -1))
|
|
|
|
|
pue.add_child(Node.s32("point", -1))
|
|
|
|
|
pue.add_child(Node.s32("value0", -1))
|
|
|
|
|
pue.add_child(Node.s32("value1", -1))
|
|
|
|
|
pue.add_child(Node.s32("value2", -1))
|
|
|
|
|
pue.add_child(Node.s32("value3", -1))
|
|
|
|
|
pue.add_child(Node.s32("value4", -1))
|
|
|
|
|
pue.add_child(Node.s32("start_time", -1))
|
|
|
|
|
pue.add_child(Node.s32("end_time", -1))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
return root
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
def unformat_profile(
|
|
|
|
|
self, userid: UserID, request: Node, oldprofile: Profile
|
|
|
|
|
) -> Profile:
|
2019-12-08 22:43:49 +01:00
|
|
|
|
game_config = self.get_game_config()
|
2021-09-07 19:56:15 +02:00
|
|
|
|
newprofile = oldprofile.clone()
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Save base player profile info
|
2022-10-15 20:56:30 +02:00
|
|
|
|
newprofile.replace_int(
|
|
|
|
|
"lid", ID.parse_machine_id(request.child_value("pdata/account/lid"))
|
|
|
|
|
)
|
|
|
|
|
newprofile.replace_str("name", request.child_value("pdata/base/name"))
|
|
|
|
|
newprofile.replace_int("exp", request.child_value("pdata/base/exp"))
|
|
|
|
|
newprofile.replace_int("lvl", request.child_value("pdata/base/lvl"))
|
|
|
|
|
newprofile.replace_int("mg", request.child_value("pdata/base/mg"))
|
|
|
|
|
newprofile.replace_int("ap", request.child_value("pdata/base/ap"))
|
|
|
|
|
newprofile.replace_int("money", request.child_value("pdata/base/money"))
|
|
|
|
|
newprofile.replace_int("class", request.child_value("pdata/base/class"))
|
|
|
|
|
newprofile.replace_int("class_ar", request.child_value("pdata/base/class_ar"))
|
|
|
|
|
newprofile.replace_int("upper_pt", request.child_value("pdata/base/upper_pt"))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Save stamps
|
2022-10-15 20:56:30 +02:00
|
|
|
|
stampdict = newprofile.get_dict("stamp")
|
|
|
|
|
stamp = request.child("pdata/stamp")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
if stamp:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
stampdict.replace_int_array("stmpcnt", 10, stamp.child_value("stmpcnt"))
|
|
|
|
|
stampdict.replace_int("area", stamp.child_value("area"))
|
|
|
|
|
stampdict.replace_int("prfvst", stamp.child_value("prfvst"))
|
|
|
|
|
newprofile.replace_dict("stamp", stampdict)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Save quest stuff
|
2022-10-15 20:56:30 +02:00
|
|
|
|
questdict = newprofile.get_dict("quest")
|
|
|
|
|
quest = request.child("pdata/quest")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
if quest:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
questdict.replace_int("eye_color", quest.child_value("eye_color"))
|
|
|
|
|
questdict.replace_int("body_color", quest.child_value("body_color"))
|
|
|
|
|
questdict.replace_int("item", quest.child_value("item"))
|
|
|
|
|
newprofile.replace_dict("quest", questdict)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Save player dojo
|
2022-10-15 20:56:30 +02:00
|
|
|
|
dojo = request.child("pdata/dojo")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
if dojo:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
dojoid = dojo.child_value("class")
|
|
|
|
|
clear_type = dojo.child_value("clear_type")
|
|
|
|
|
ar = dojo.child_value("t_ar")
|
|
|
|
|
score = dojo.child_value("t_score")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Figure out timestamp stuff
|
2022-10-15 20:56:30 +02:00
|
|
|
|
data = (
|
|
|
|
|
self.data.local.user.get_achievement(
|
|
|
|
|
self.game,
|
|
|
|
|
self.version,
|
|
|
|
|
userid,
|
|
|
|
|
dojoid,
|
|
|
|
|
"dojo",
|
|
|
|
|
)
|
|
|
|
|
or ValidatedDict()
|
|
|
|
|
)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
if ar >= data.get_int("ar"):
|
2019-12-08 22:43:49 +01:00
|
|
|
|
# We set a new achievement rate, keep the new values
|
|
|
|
|
record_time = Time.now()
|
|
|
|
|
else:
|
|
|
|
|
# We didn't, keep the old values for achievement rate, but
|
|
|
|
|
# override score and clear_type only if they were better.
|
2022-10-15 20:56:30 +02:00
|
|
|
|
record_time = data.get_int("record_timestamp")
|
|
|
|
|
ar = data.get_int("ar")
|
|
|
|
|
score = max(score, data.get_int("score"))
|
|
|
|
|
clear_type = max(clear_type, data.get_int("clear_type"))
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
play_time = Time.now()
|
2022-10-15 20:56:30 +02:00
|
|
|
|
plays = data.get_int("plays") + 1
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
self.data.local.user.put_achievement(
|
|
|
|
|
self.game,
|
|
|
|
|
self.version,
|
|
|
|
|
userid,
|
|
|
|
|
dojoid,
|
2022-10-15 20:56:30 +02:00
|
|
|
|
"dojo",
|
2019-12-08 22:43:49 +01:00
|
|
|
|
{
|
2022-10-15 20:56:30 +02:00
|
|
|
|
"clear_type": clear_type,
|
|
|
|
|
"ar": ar,
|
|
|
|
|
"score": score,
|
|
|
|
|
"plays": plays,
|
|
|
|
|
"play_timestamp": play_time,
|
|
|
|
|
"record_timestamp": record_time,
|
2019-12-08 22:43:49 +01:00
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Save player config
|
2022-10-15 20:56:30 +02:00
|
|
|
|
configdict = newprofile.get_dict("config")
|
|
|
|
|
config = request.child("pdata/config")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
if config:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
configdict.replace_int("msel_bgm", config.child_value("msel_bgm"))
|
|
|
|
|
configdict.replace_int(
|
|
|
|
|
"narrowdown_type", config.child_value("narrowdown_type")
|
|
|
|
|
)
|
|
|
|
|
configdict.replace_int("icon_id", config.child_value("icon_id"))
|
|
|
|
|
configdict.replace_int("byword_0", config.child_value("byword_0"))
|
|
|
|
|
configdict.replace_int("byword_1", config.child_value("byword_1"))
|
|
|
|
|
configdict.replace_bool(
|
|
|
|
|
"is_auto_byword_0", config.child_value("is_auto_byword_0")
|
|
|
|
|
)
|
|
|
|
|
configdict.replace_bool(
|
|
|
|
|
"is_auto_byword_1", config.child_value("is_auto_byword_1")
|
|
|
|
|
)
|
|
|
|
|
configdict.replace_int("mrec_type", config.child_value("mrec_type"))
|
|
|
|
|
configdict.replace_int("tab_sel", config.child_value("tab_sel"))
|
|
|
|
|
configdict.replace_int("card_disp", config.child_value("card_disp"))
|
|
|
|
|
configdict.replace_int(
|
|
|
|
|
"score_tab_disp", config.child_value("score_tab_disp")
|
|
|
|
|
)
|
|
|
|
|
configdict.replace_int("last_music_id", config.child_value("last_music_id"))
|
|
|
|
|
configdict.replace_int(
|
|
|
|
|
"last_note_grade", config.child_value("last_note_grade")
|
|
|
|
|
)
|
|
|
|
|
configdict.replace_int("sort_type", config.child_value("sort_type"))
|
|
|
|
|
configdict.replace_int(
|
|
|
|
|
"rival_panel_type", config.child_value("rival_panel_type")
|
|
|
|
|
)
|
|
|
|
|
configdict.replace_int(
|
|
|
|
|
"random_entry_work", config.child_value("random_entry_work")
|
|
|
|
|
)
|
|
|
|
|
configdict.replace_int(
|
|
|
|
|
"custom_folder_work", config.child_value("custom_folder_work")
|
|
|
|
|
)
|
|
|
|
|
configdict.replace_int("folder_type", config.child_value("folder_type"))
|
|
|
|
|
configdict.replace_int(
|
|
|
|
|
"folder_lamp_type", config.child_value("folder_lamp_type")
|
|
|
|
|
)
|
|
|
|
|
configdict.replace_bool("is_tweet", config.child_value("is_tweet"))
|
|
|
|
|
configdict.replace_bool(
|
|
|
|
|
"is_link_twitter", config.child_value("is_link_twitter")
|
|
|
|
|
)
|
|
|
|
|
newprofile.replace_dict("config", configdict)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Save player custom settings
|
2022-10-15 20:56:30 +02:00
|
|
|
|
customdict = newprofile.get_dict("custom")
|
|
|
|
|
custom = request.child("pdata/custom")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
if custom:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
customdict.replace_int("st_shot", custom.child_value("st_shot"))
|
|
|
|
|
customdict.replace_int("st_frame", custom.child_value("st_frame"))
|
|
|
|
|
customdict.replace_int("st_expl", custom.child_value("st_expl"))
|
|
|
|
|
customdict.replace_int("st_bg", custom.child_value("st_bg"))
|
|
|
|
|
customdict.replace_int("st_shot_vol", custom.child_value("st_shot_vol"))
|
|
|
|
|
customdict.replace_int("st_bg_bri", custom.child_value("st_bg_bri"))
|
|
|
|
|
customdict.replace_int("st_obj_size", custom.child_value("st_obj_size"))
|
|
|
|
|
customdict.replace_int("st_jr_gauge", custom.child_value("st_jr_gauge"))
|
|
|
|
|
customdict.replace_int("st_clr_gauge", custom.child_value("st_clr_gauge"))
|
|
|
|
|
customdict.replace_int("st_jdg_disp", custom.child_value("st_jdg_disp"))
|
|
|
|
|
customdict.replace_int("st_tm_disp", custom.child_value("st_tm_disp"))
|
|
|
|
|
customdict.replace_int("st_rnd", custom.child_value("st_rnd"))
|
|
|
|
|
customdict.replace_int("st_hazard", custom.child_value("st_hazard"))
|
|
|
|
|
customdict.replace_int("st_clr_cond", custom.child_value("st_clr_cond"))
|
|
|
|
|
customdict.replace_int_array("schat_0", 10, custom.child_value("schat_0"))
|
|
|
|
|
customdict.replace_int_array("schat_1", 10, custom.child_value("schat_1"))
|
|
|
|
|
customdict.replace_int("cheer_voice", custom.child_value("cheer_voice"))
|
|
|
|
|
customdict.replace_int(
|
|
|
|
|
"same_time_note_disp", custom.child_value("same_time_note_disp")
|
|
|
|
|
)
|
|
|
|
|
newprofile.replace_dict("custom", customdict)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Save player parameter info
|
2022-10-15 20:56:30 +02:00
|
|
|
|
params = request.child("pdata/player_param")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
if params:
|
|
|
|
|
for child in params.children:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
if child.name != "item":
|
2019-12-08 22:43:49 +01:00
|
|
|
|
continue
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
item_type = child.child_value("type")
|
|
|
|
|
bank = child.child_value("bank")
|
|
|
|
|
paramdata = child.child_value("data") or []
|
2019-12-08 22:43:49 +01:00
|
|
|
|
while len(paramdata) < 256:
|
|
|
|
|
paramdata.append(0)
|
|
|
|
|
self.data.local.user.put_achievement(
|
|
|
|
|
self.game,
|
|
|
|
|
self.version,
|
|
|
|
|
userid,
|
|
|
|
|
bank,
|
2022-10-15 20:56:30 +02:00
|
|
|
|
f"player_param_{item_type}",
|
2019-12-08 22:43:49 +01:00
|
|
|
|
{
|
2022-10-15 20:56:30 +02:00
|
|
|
|
"data": paramdata,
|
2019-12-08 22:43:49 +01:00
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Save player episode info
|
2022-10-15 20:56:30 +02:00
|
|
|
|
episode = request.child("pdata/episode")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
if episode:
|
|
|
|
|
for child in episode.children:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
if child.name != "info":
|
2019-12-08 22:43:49 +01:00
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
# I assume this is copypasta, but I want to be sure
|
2022-10-15 20:56:30 +02:00
|
|
|
|
extid = child.child_value("user_id")
|
2021-08-20 06:43:13 +02:00
|
|
|
|
if extid != newprofile.extid:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
raise Exception(
|
|
|
|
|
f"Unexpected user ID, got {extid} expecting {newprofile.extid}"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
episode_type = child.child_value("type")
|
|
|
|
|
episode_value0 = child.child_value("value0")
|
|
|
|
|
episode_value1 = child.child_value("value1")
|
|
|
|
|
episode_text = child.child_value("text")
|
|
|
|
|
episode_time = child.child_value("time")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
self.data.local.user.put_achievement(
|
|
|
|
|
self.game,
|
|
|
|
|
self.version,
|
|
|
|
|
userid,
|
|
|
|
|
episode_type,
|
2022-10-15 20:56:30 +02:00
|
|
|
|
"episode",
|
2019-12-08 22:43:49 +01:00
|
|
|
|
{
|
2022-10-15 20:56:30 +02:00
|
|
|
|
"value0": episode_value0,
|
|
|
|
|
"value1": episode_value1,
|
|
|
|
|
"text": episode_text,
|
|
|
|
|
"time": episode_time,
|
2019-12-08 22:43:49 +01:00
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Save released info
|
2022-10-15 20:56:30 +02:00
|
|
|
|
released = request.child("pdata/released")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
if released:
|
|
|
|
|
for child in released.children:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
if child.name != "info":
|
2019-12-08 22:43:49 +01:00
|
|
|
|
continue
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
item_id = child.child_value("id")
|
|
|
|
|
item_type = child.child_value("type")
|
|
|
|
|
param = child.child_value("param")
|
|
|
|
|
if game_config.get_bool("force_unlock_songs") and item_type == 0:
|
2019-12-08 22:43:49 +01:00
|
|
|
|
# Don't save unlocks when we're force unlocking
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
self.data.local.user.put_achievement(
|
|
|
|
|
self.game,
|
|
|
|
|
self.version,
|
|
|
|
|
userid,
|
|
|
|
|
item_id,
|
2022-10-15 20:56:30 +02:00
|
|
|
|
f"item_{item_type}",
|
2019-12-08 22:43:49 +01:00
|
|
|
|
{
|
2022-10-15 20:56:30 +02:00
|
|
|
|
"param": param,
|
2019-12-08 22:43:49 +01:00
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Save announce info
|
2022-10-15 20:56:30 +02:00
|
|
|
|
announce = request.child("pdata/announce")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
if announce:
|
|
|
|
|
for child in announce.children:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
if child.name != "info":
|
2019-12-08 22:43:49 +01:00
|
|
|
|
continue
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
announce_id = child.child_value("id")
|
|
|
|
|
announce_type = child.child_value("type")
|
|
|
|
|
param = child.child_value("param")
|
|
|
|
|
need = child.child_value("bneedannounce")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
self.data.local.user.put_achievement(
|
|
|
|
|
self.game,
|
|
|
|
|
self.version,
|
|
|
|
|
userid,
|
|
|
|
|
announce_id,
|
2022-10-15 20:56:30 +02:00
|
|
|
|
f"announcement_{announce_type}",
|
2019-12-08 22:43:49 +01:00
|
|
|
|
{
|
2022-10-15 20:56:30 +02:00
|
|
|
|
"param": param,
|
|
|
|
|
"need": need,
|
2019-12-08 22:43:49 +01:00
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Grab any new rivals added during this play session
|
2022-10-15 20:56:30 +02:00
|
|
|
|
rivalnode = request.child("pdata/rival")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
if rivalnode:
|
|
|
|
|
for child in rivalnode.children:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
if child.name != "r":
|
2019-12-08 22:43:49 +01:00
|
|
|
|
continue
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
extid = child.child_value("id")
|
|
|
|
|
other_userid = self.data.remote.user.from_extid(
|
|
|
|
|
self.game, self.version, extid
|
|
|
|
|
)
|
2019-12-08 22:43:49 +01:00
|
|
|
|
if other_userid is None:
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
self.data.local.user.put_link(
|
|
|
|
|
self.game,
|
|
|
|
|
self.version,
|
|
|
|
|
userid,
|
2022-10-15 20:56:30 +02:00
|
|
|
|
"rival",
|
2019-12-08 22:43:49 +01:00
|
|
|
|
other_userid,
|
|
|
|
|
{},
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Grab any new records set during this play session
|
2022-10-15 20:56:30 +02:00
|
|
|
|
songplays = request.child("pdata/stglog")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
if songplays:
|
|
|
|
|
for child in songplays.children:
|
2022-10-15 20:56:30 +02:00
|
|
|
|
if child.name != "log":
|
2019-12-08 22:43:49 +01:00
|
|
|
|
continue
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
songid = child.child_value("mid")
|
|
|
|
|
chart = child.child_value("ng")
|
|
|
|
|
clear_type = child.child_value("ct")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
if songid == 0 and chart == 0 and clear_type == -1:
|
|
|
|
|
# Dummy song save during profile create
|
|
|
|
|
continue
|
|
|
|
|
|
2022-10-15 20:56:30 +02:00
|
|
|
|
points = child.child_value("sc")
|
|
|
|
|
achievement_rate = child.child_value("ar")
|
|
|
|
|
param = child.child_value("param")
|
|
|
|
|
miss_count = child.child_value("jt_ms")
|
2019-12-08 22:43:49 +01:00
|
|
|
|
|
|
|
|
|
# Param is some random bits along with the combo type
|
|
|
|
|
combo_type = param & 0x3
|
|
|
|
|
param = param ^ combo_type
|
|
|
|
|
|
|
|
|
|
clear_type = self.__game_to_db_clear_type(clear_type)
|
|
|
|
|
combo_type = self.__game_to_db_combo_type(combo_type, miss_count)
|
|
|
|
|
self.update_score(
|
|
|
|
|
userid,
|
|
|
|
|
songid,
|
|
|
|
|
chart,
|
|
|
|
|
points,
|
|
|
|
|
achievement_rate,
|
|
|
|
|
clear_type,
|
|
|
|
|
combo_type,
|
|
|
|
|
miss_count,
|
|
|
|
|
param=param,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Keep track of play statistics
|
|
|
|
|
self.update_play_statistics(userid)
|
|
|
|
|
|
|
|
|
|
return newprofile
|