From 87d699e05cf21537452645ef814b662cae165a21 Mon Sep 17 00:00:00 2001 From: Jennifer Taylor Date: Mon, 14 Nov 2022 01:54:19 +0000 Subject: [PATCH] Add force unlock flag to all of Jubeat. --- bemani/backend/jubeat/clan.py | 77 +++++++++++++++++++--- bemani/backend/jubeat/festo.py | 78 +++++++++++++++++++--- bemani/backend/jubeat/prop.py | 77 +++++++++++++++++++--- bemani/backend/jubeat/qubell.py | 78 +++++++++++++++++++--- bemani/backend/jubeat/saucer.py | 89 +++++++++++++++++++++----- bemani/backend/jubeat/saucerfulfill.py | 89 +++++++++++++++++++++----- 6 files changed, 420 insertions(+), 68 deletions(-) diff --git a/bemani/backend/jubeat/clan.py b/bemani/backend/jubeat/clan.py index bdce316..72f205e 100644 --- a/bemani/backend/jubeat/clan.py +++ b/bemani/backend/jubeat/clan.py @@ -135,6 +135,22 @@ class JubeatClan( ) return events + @classmethod + def get_settings(cls) -> Dict[str, Any]: + """ + Return all of our front-end modifiably settings. + """ + return { + "bools": [ + { + "name": "Force Unlock All Songs", + "tip": "Forces all songs to be available by default", + "category": "game_config", + "setting": "force_song_unlock", + }, + ], + } + def __get_course_list(self) -> List[Dict[str, Any]]: return [ # Papricapcap courses @@ -1549,10 +1565,16 @@ class JubeatClan( data = Node.void("data") root.add_child(data) + # Figure out if we're force-unlocking songs. + game_config = self.get_game_config() + force_unlock = game_config.get_bool("force_song_unlock") + # Calculate all of our achievement-backed entities. achievements = self.data.local.user.get_achievements( self.game, self.version, userid ) + owned_songs: Set[int] = set() + owned_secrets: Set[int] = set() event_completion: Dict[int, bool] = {} course_completion: Dict[int, ValidatedDict] = {} owned_emblems: Set[int] = set() @@ -1565,6 +1587,10 @@ class JubeatClan( course_completion[achievement.id] = achievement.data elif achievement.type == "emblem": owned_emblems.add(achievement.id) + elif achievement.type == "song": + owned_songs.add(achievement.id) + elif achievement.type == "secret": + owned_secrets.add(achievement.id) # Make sure we grant ownership of default main parts. default_emblems = self.default_select_jbox() @@ -1659,7 +1685,10 @@ class JubeatClan( ) item.add_child( Node.s32_array( - "secret_list", profile.get_int_array("secret_list", 64, [-1] * 64) + "secret_list", + ([-1] * 64) + if force_unlock + else self.create_owned_items(owned_songs, 64), ) ) item.add_child( @@ -1695,7 +1724,10 @@ class JubeatClan( item.add_child(new) new.add_child( Node.s32_array( - "secret_list", profile.get_int_array("secret_list_new", 64, [-1] * 64) + "secret_list", + ([-1] * 64) + if force_unlock + else self.create_owned_items(owned_secrets, 64), ) ) new.add_child( @@ -2039,6 +2071,11 @@ class JubeatClan( newprofile.replace_bool("saved", True) data = request.child("data") + # Figure out if we're force-unlocking songs. If we are, we don't want to persist + # secret stuff otherwise the game will accidentally unlock everything in the profile. + game_config = self.get_game_config() + force_unlock = game_config.get_bool("force_song_unlock") + # Grab system information sysinfo = data.child("info") @@ -2101,9 +2138,6 @@ class JubeatClan( newprofile.replace_int_array( "music_list", 64, item.child_value("music_list") ) - newprofile.replace_int_array( - "secret_list", 64, item.child_value("secret_list") - ) newprofile.replace_int_array( "theme_list", 16, item.child_value("theme_list") ) @@ -2120,6 +2154,21 @@ class JubeatClan( "commu_list", 16, item.child_value("commu_list") ) + if not force_unlock: + # Don't persist if we're force-unlocked, this data will be bogus. + owned_songs = self.calculate_owned_items( + item.child_value("secret_list") + ) + for index in owned_songs: + self.data.local.user.put_achievement( + self.game, + self.version, + userid, + index, + "song", + {}, + ) + owned_emblems = self.calculate_owned_items(item.child_value("emblem_list")) for index in owned_emblems: self.data.local.user.put_achievement( @@ -2133,9 +2182,6 @@ class JubeatClan( newitem = item.child("new") if newitem is not None: - newprofile.replace_int_array( - "secret_list_new", 64, newitem.child_value("secret_list") - ) newprofile.replace_int_array( "theme_list_new", 16, newitem.child_value("theme_list") ) @@ -2143,6 +2189,21 @@ class JubeatClan( "marker_list_new", 16, newitem.child_value("marker_list") ) + if not force_unlock: + # Don't persist if we're force-unlocked, this data will be bogus. + owned_secrets = self.calculate_owned_items( + newitem.child_value("secret_list") + ) + for index in owned_secrets: + self.data.local.user.put_achievement( + self.game, + self.version, + userid, + index, + "secret", + {}, + ) + # Grab categories stuff fill_in_category = player.child("fill_in_category") if fill_in_category is not None: diff --git a/bemani/backend/jubeat/festo.py b/bemani/backend/jubeat/festo.py index 1e52a6e..e021e9b 100644 --- a/bemani/backend/jubeat/festo.py +++ b/bemani/backend/jubeat/festo.py @@ -305,6 +305,12 @@ class JubeatFesto( "category": "game_config", "setting": "50th_anniversary", }, + { + "name": "Force Unlock All Songs", + "tip": "Forces all songs to be available by default", + "category": "game_config", + "setting": "force_song_unlock", + }, ], } @@ -2426,10 +2432,16 @@ class JubeatFesto( data = Node.void("data") root.add_child(data) + # Figure out if we're force-unlocking songs. + game_config = self.get_game_config() + force_unlock = game_config.get_bool("force_song_unlock") + # Calculate all of our achievement-backed entities. achievements = self.data.local.user.get_achievements( self.game, self.version, userid ) + owned_songs: Set[int] = set() + owned_secrets: Set[int] = set() owned_emblems: Set[int] = set() event_completion: Dict[int, bool] = {} course_completion: Dict[int, ValidatedDict] = {} @@ -2442,6 +2454,10 @@ class JubeatFesto( course_completion[achievement.id] = achievement.data elif achievement.type == "emblem": owned_emblems.add(achievement.id) + elif achievement.type == "song": + owned_songs.add(achievement.id) + elif achievement.type == "secret": + owned_secrets.add(achievement.id) # Make sure we grant ownership of default main parts. default_emblems = self.default_select_jbox() @@ -2524,17 +2540,24 @@ class JubeatFesto( partslist[1] = default_main settings.add_child(Node.s16_array("emblem", partslist)) - # Secret unlocks, the game is too complicated and server-controlled to handle these correctly. item = Node.void("item") player.add_child(item) + + # Default music availability, I think? The game doesn't seem to make much use of this, so I think + # we can safely set it to all 1's much like we do the open_music_list bitfield in global settings. item.add_child( Node.s32_array( "music_list", profile.get_int_array("music_list", 64, [-1] * 64) ) ) + + # Song unlocks, force everything on if force unlocked, otherwise default to what the game granted. item.add_child( Node.s32_array( - "secret_list", profile.get_int_array("secret_list", 64, [-1] * 64) + "secret_list", + ([-1] * 64) + if force_unlock + else self.create_owned_items(owned_songs, 64), ) ) @@ -2572,11 +2595,19 @@ class JubeatFesto( ) ) + # I have no idea what these are for. I figured it was for the server to grant songs/themes/markers + # outside of gameplay, but the game doesn't seem to react to setting values here. So, lets set them + # to all 1's and move on. Tracing the handling of this shows that the game usually sets the same bit + # in both the secret list above and this one, and doesn't seem to care about parsing the values as + # they come in. new = Node.void("new") item.add_child(new) new.add_child( Node.s32_array( - "secret_list", profile.get_int_array("secret_list_new", 64, [-1] * 64) + "secret_list", + ([-1] * 64) + if force_unlock + else self.create_owned_items(owned_secrets, 64), ) ) new.add_child( @@ -2871,6 +2902,11 @@ class JubeatFesto( newprofile.replace_bool("saved", True) data = request.child("data") + # Figure out if we're force-unlocking songs. If we are, we don't want to persist + # secret stuff otherwise the game will accidentally unlock everything in the profile. + game_config = self.get_game_config() + force_unlock = game_config.get_bool("force_song_unlock") + # Grab system information sysinfo = data.child("info") @@ -2933,9 +2969,6 @@ class JubeatFesto( newprofile.replace_int_array( "music_list", 64, item.child_value("music_list") ) - newprofile.replace_int_array( - "secret_list", 64, item.child_value("secret_list") - ) newprofile.replace_int_array( "theme_list", 16, item.child_value("theme_list") ) @@ -2952,6 +2985,21 @@ class JubeatFesto( "commu_list", 16, item.child_value("commu_list") ) + if not force_unlock: + # Don't persist if we're force-unlocked, this data will be bogus. + owned_songs = self.calculate_owned_items( + item.child_value("secret_list") + ) + for index in owned_songs: + self.data.local.user.put_achievement( + self.game, + self.version, + userid, + index, + "song", + {}, + ) + owned_emblems = self.calculate_owned_items(item.child_value("emblem_list")) for index in owned_emblems: self.data.local.user.put_achievement( @@ -2965,9 +3013,6 @@ class JubeatFesto( newitem = item.child("new") if newitem is not None: - newprofile.replace_int_array( - "secret_list_new", 64, newitem.child_value("secret_list") - ) newprofile.replace_int_array( "theme_list_new", 16, newitem.child_value("theme_list") ) @@ -2975,6 +3020,21 @@ class JubeatFesto( "marker_list_new", 16, newitem.child_value("marker_list") ) + if not force_unlock: + # Don't persist if we're force-unlocked, this data will be bogus. + owned_secrets = self.calculate_owned_items( + newitem.child_value("secret_list") + ) + for index in owned_secrets: + self.data.local.user.put_achievement( + self.game, + self.version, + userid, + index, + "secret", + {}, + ) + # Grab categories stuff fill_in_category = player.child("fill_in_category") if fill_in_category is not None: diff --git a/bemani/backend/jubeat/prop.py b/bemani/backend/jubeat/prop.py index e995add..2ef0d8a 100644 --- a/bemani/backend/jubeat/prop.py +++ b/bemani/backend/jubeat/prop.py @@ -80,6 +80,22 @@ class JubeatProp( def previous_version(self) -> Optional[JubeatBase]: return JubeatSaucerFulfill(self.data, self.config, self.model) + @classmethod + def get_settings(cls) -> Dict[str, Any]: + """ + Return all of our front-end modifiably settings. + """ + return { + "bools": [ + { + "name": "Force Unlock All Songs", + "tip": "Forces all songs to be available by default", + "category": "game_config", + "setting": "force_song_unlock", + }, + ], + } + @classmethod def __class_to_rank(cls, cur_class: int, cur_subclass: int) -> int: """ @@ -897,14 +913,24 @@ class JubeatProp( data = Node.void("data") root.add_child(data) + # Figure out if we're force-unlocking songs. + game_config = self.get_game_config() + force_unlock = game_config.get_bool("force_song_unlock") + # Allow figuring out owned emblems. achievements = self.data.local.user.get_achievements( self.game, self.version, userid ) + owned_songs: Set[int] = set() + owned_secrets: Set[int] = set() owned_emblems: Set[int] = set() for achievement in achievements: if achievement.type == "emblem": owned_emblems.add(achievement.id) + elif achievement.type == "song": + owned_songs.add(achievement.id) + elif achievement.type == "secret": + owned_secrets.add(achievement.id) # Make sure we grant ownership of default main parts. default_emblems = self.default_select_jbox() @@ -1002,7 +1028,10 @@ class JubeatProp( ) item.add_child( Node.s32_array( - "secret_list", profile.get_int_array("secret_list", 32, [-1] * 32) + "secret_list", + ([-1] * 32) + if force_unlock + else self.create_owned_items(owned_songs, 32), ) ) item.add_child(Node.s16("theme_list", profile.get_int("theme_list", -1))) @@ -1029,7 +1058,10 @@ class JubeatProp( item.add_child(new) new.add_child( Node.s32_array( - "secret_list", profile.get_int_array("secret_list_new", 32, [-1] * 32) + "secret_list", + ([-1] * 32) + if force_unlock + else self.create_owned_items(owned_secrets, 32), ) ) new.add_child(Node.s16("theme_list", profile.get_int("theme_list_new", -1))) @@ -1264,6 +1296,11 @@ class JubeatProp( newprofile.replace_bool("saved", True) data = request.child("data") + # Figure out if we're force-unlocking songs. If we are, we don't want to persist + # secret stuff otherwise the game will accidentally unlock everything in the profile. + game_config = self.get_game_config() + force_unlock = game_config.get_bool("force_song_unlock") + # Grab system information sysinfo = data.child("info") @@ -1329,9 +1366,6 @@ class JubeatProp( # Grab unlock progress item = player.child("item") if item is not None: - newprofile.replace_int_array( - "secret_list", 32, item.child_value("secret_list") - ) newprofile.replace_int_array( "title_list", 160, item.child_value("title_list") ) @@ -1346,6 +1380,21 @@ class JubeatProp( "music_list", 32, item.child_value("music_list") ) + if not force_unlock: + # Don't persist if we're force-unlocked, this data will be bogus. + owned_songs = self.calculate_owned_items( + item.child_value("secret_list") + ) + for index in owned_songs: + self.data.local.user.put_achievement( + self.game, + self.version, + userid, + index, + "song", + {}, + ) + owned_emblems = self.calculate_owned_items(item.child_value("emblem_list")) for index in owned_emblems: self.data.local.user.put_achievement( @@ -1359,9 +1408,6 @@ class JubeatProp( newitem = item.child("new") if newitem is not None: - newprofile.replace_int_array( - "secret_list_new", 32, newitem.child_value("secret_list") - ) newprofile.replace_int( "theme_list_new", newitem.child_value("theme_list") ) @@ -1369,6 +1415,21 @@ class JubeatProp( "marker_list_new", 2, newitem.child_value("marker_list") ) + if not force_unlock: + # Don't persist if we're force-unlocked, this data will be bogus. + owned_secrets = self.calculate_owned_items( + newitem.child_value("secret_list") + ) + for index in owned_secrets: + self.data.local.user.put_achievement( + self.game, + self.version, + userid, + index, + "secret", + {}, + ) + # Career progression career = player.child("career") careerdict = newprofile.get_dict("career") diff --git a/bemani/backend/jubeat/qubell.py b/bemani/backend/jubeat/qubell.py index 4d922b2..040e9c8 100644 --- a/bemani/backend/jubeat/qubell.py +++ b/bemani/backend/jubeat/qubell.py @@ -103,6 +103,22 @@ class JubeatQubell( ) return events + @classmethod + def get_settings(cls) -> Dict[str, Any]: + """ + Return all of our front-end modifiably settings. + """ + return { + "bools": [ + { + "name": "Force Unlock All Songs", + "tip": "Forces all songs to be available by default", + "category": "game_config", + "setting": "force_song_unlock", + }, + ], + } + def __get_global_info(self) -> Node: info = Node.void("info") @@ -715,13 +731,23 @@ class JubeatQubell( data = Node.void("data") root.add_child(data) + # Figure out if we're force-unlocking songs. + game_config = self.get_game_config() + force_unlock = game_config.get_bool("force_song_unlock") + achievements = self.data.local.user.get_achievements( self.game, self.version, userid ) + owned_songs: Set[int] = set() + owned_secrets: Set[int] = set() owned_emblems: Set[int] = set() for achievement in achievements: if achievement.type == "emblem": owned_emblems.add(achievement.id) + elif achievement.type == "song": + owned_songs.add(achievement.id) + elif achievement.type == "secret": + owned_secrets.add(achievement.id) # Make sure we grant ownership of default main parts. default_emblems = self.default_select_jbox() @@ -823,7 +849,10 @@ class JubeatQubell( ) item.add_child( Node.s32_array( - "secret_list", profile.get_int_array("secret_list", 64, [-1] * 64) + "secret_list", + ([-1] * 64) + if force_unlock + else self.create_owned_items(owned_songs, 64), ) ) item.add_child( @@ -854,7 +883,10 @@ class JubeatQubell( item.add_child(new) new.add_child( Node.s32_array( - "secret_list", profile.get_int_array("secret_list_new", 64, [-1] * 64) + "secret_list", + ([-1] * 64) + if force_unlock + else self.create_owned_items(owned_secrets, 64), ) ) new.add_child( @@ -1151,7 +1183,6 @@ class JubeatQubell( def format_scores( self, userid: UserID, profile: Profile, scores: List[Score] ) -> Node: - root = Node.void("gametop") datanode = Node.void("data") root.add_child(datanode) @@ -1255,6 +1286,11 @@ class JubeatQubell( newprofile.replace_bool("saved", True) data = request.child("data") + # Figure out if we're force-unlocking songs. If we are, we don't want to persist + # secret stuff otherwise the game will accidentally unlock everything in the profile. + game_config = self.get_game_config() + force_unlock = game_config.get_bool("force_song_unlock") + # Grab system information sysinfo = data.child("info") @@ -1320,9 +1356,6 @@ class JubeatQubell( newprofile.replace_int_array( "music_list", 64, item.child_value("music_list") ) - newprofile.replace_int_array( - "secret_list", 64, item.child_value("secret_list") - ) newprofile.replace_int_array( "theme_list", 16, item.child_value("theme_list") ) @@ -1336,6 +1369,21 @@ class JubeatQubell( "parts_list", 160, item.child_value("parts_list") ) + if not force_unlock: + # Don't persist if we're force-unlocked, this data will be bogus. + owned_songs = self.calculate_owned_items( + item.child_value("secret_list") + ) + for index in owned_songs: + self.data.local.user.put_achievement( + self.game, + self.version, + userid, + index, + "song", + {}, + ) + owned_emblems = self.calculate_owned_items(item.child_value("emblem_list")) for index in owned_emblems: self.data.local.user.put_achievement( @@ -1349,9 +1397,6 @@ class JubeatQubell( newitem = item.child("new") if newitem is not None: - newprofile.replace_int_array( - "secret_list_new", 64, newitem.child_value("secret_list") - ) newprofile.replace_int_array( "theme_list_new", 16, newitem.child_value("theme_list") ) @@ -1359,6 +1404,21 @@ class JubeatQubell( "marker_list_new", 16, newitem.child_value("marker_list") ) + if not force_unlock: + # Don't persist if we're force-unlocked, this data will be bogus. + owned_secrets = self.calculate_owned_items( + newitem.child_value("secret_list") + ) + for index in owned_secrets: + self.data.local.user.put_achievement( + self.game, + self.version, + userid, + index, + "secret", + {}, + ) + # jbox stuff jbox = player.child("jbox") jboxdict = newprofile.get_dict("jbox") diff --git a/bemani/backend/jubeat/saucer.py b/bemani/backend/jubeat/saucer.py index 2925d5f..277f85f 100644 --- a/bemani/backend/jubeat/saucer.py +++ b/bemani/backend/jubeat/saucer.py @@ -1,6 +1,6 @@ # vim: set fileencoding=utf-8 import random -from typing import Any, Dict, List, Optional, Tuple +from typing import Any, Dict, List, Optional, Set, Tuple from bemani.backend.base import Status from bemani.backend.jubeat.base import JubeatBase @@ -79,6 +79,22 @@ class JubeatSaucer( ) return events + @classmethod + def get_settings(cls) -> Dict[str, Any]: + """ + Return all of our front-end modifiably settings. + """ + return { + "bools": [ + { + "name": "Force Unlock All Songs", + "tip": "Forces all songs to be available by default", + "category": "game_config", + "setting": "force_song_unlock", + }, + ], + } + def handle_shopinfo_regist_request(self, request: Node) -> Node: # Update the name of this cab for admin purposes self.update_machine_name(request.child_value("shop/name")) @@ -207,6 +223,22 @@ class JubeatSaucer( player = Node.void("player") data.add_child(player) + # Figure out if we're force-unlocking songs. + game_config = self.get_game_config() + force_unlock = game_config.get_bool("force_song_unlock") + + # Allow figuring out owned songs. + achievements = self.data.local.user.get_achievements( + self.game, self.version, userid + ) + owned_songs: Set[int] = set() + owned_secrets: Set[int] = set() + for achievement in achievements: + if achievement.type == "song": + owned_songs.add(achievement.id) + elif achievement.type == "secret": + owned_secrets.add(achievement.id) + # Player info and statistics info = Node.void("info") player.add_child(info) @@ -247,11 +279,9 @@ class JubeatSaucer( item.add_child( Node.s32_array( "secret_list", - profile.get_int_array( - "secret_list", - 32, - [-1] * 32, - ), + ([-1] * 32) + if force_unlock + else self.create_owned_items(owned_songs, 32), ) ) item.add_child( @@ -281,11 +311,9 @@ class JubeatSaucer( new.add_child( Node.s32_array( "secret_list", - profile.get_int_array( - "secret_list_new", - 32, - [-1] * 32, - ), + ([-1] * 32) + if force_unlock + else self.create_owned_items(owned_secrets, 32), ) ) new.add_child( @@ -689,6 +717,11 @@ class JubeatSaucer( newprofile.replace_bool("saved", True) data = request.child("data") + # Figure out if we're force-unlocking songs. If we are, we don't want to persist + # secret stuff otherwise the game will accidentally unlock everything in the profile. + game_config = self.get_game_config() + force_unlock = game_config.get_bool("force_song_unlock") + # Grab player information player = data.child("player") @@ -722,9 +755,6 @@ class JubeatSaucer( # Grab unlock progress item = player.child("item") if item is not None: - newprofile.replace_int_array( - "secret_list", 32, item.child_value("secret_list") - ) newprofile.replace_int_array( "title_list", 96, item.child_value("title_list") ) @@ -735,9 +765,6 @@ class JubeatSaucer( newprofile.replace_int_array( "parts_list", 96, item.child_value("parts_list") ) - newprofile.replace_int_array( - "secret_list_new", 32, item.child_value("secret_new") - ) newprofile.replace_int_array( "title_list_new", 96, item.child_value("title_new") ) @@ -746,6 +773,34 @@ class JubeatSaucer( "marker_list_new", 2, item.child_value("marker_new") ) + if not force_unlock: + # Don't persist if we're force-unlocked, this data will be bogus. + owned_songs = self.calculate_owned_items( + item.child_value("secret_list") + ) + for index in owned_songs: + self.data.local.user.put_achievement( + self.game, + self.version, + userid, + index, + "song", + {}, + ) + + owned_secrets = self.calculate_owned_items( + item.child_value("secret_new") + ) + for index in owned_secrets: + self.data.local.user.put_achievement( + self.game, + self.version, + userid, + index, + "secret", + {}, + ) + # Grab bistro progress bistro = player.child("bistro") if bistro is not None: diff --git a/bemani/backend/jubeat/saucerfulfill.py b/bemani/backend/jubeat/saucerfulfill.py index 1483562..c94c128 100644 --- a/bemani/backend/jubeat/saucerfulfill.py +++ b/bemani/backend/jubeat/saucerfulfill.py @@ -1,6 +1,6 @@ # vim: set fileencoding=utf-8 import random -from typing import Any, Dict, List, Optional, Tuple +from typing import Any, Dict, List, Optional, Set, Tuple from typing_extensions import Final from bemani.backend.base import Status @@ -93,6 +93,22 @@ class JubeatSaucerFulfill( ) return events + @classmethod + def get_settings(cls) -> Dict[str, Any]: + """ + Return all of our front-end modifiably settings. + """ + return { + "bools": [ + { + "name": "Force Unlock All Songs", + "tip": "Forces all songs to be available by default", + "category": "game_config", + "setting": "force_song_unlock", + }, + ], + } + def handle_shopinfo_regist_request(self, request: Node) -> Node: # Update the name of this cab for admin purposes self.update_machine_name(request.child_value("shop/name")) @@ -342,6 +358,22 @@ class JubeatSaucerFulfill( player = Node.void("player") data.add_child(player) + # Figure out if we're force-unlocking songs. + game_config = self.get_game_config() + force_unlock = game_config.get_bool("force_song_unlock") + + # Allow figuring out owned songs. + achievements = self.data.local.user.get_achievements( + self.game, self.version, userid + ) + owned_songs: Set[int] = set() + owned_secrets: Set[int] = set() + for achievement in achievements: + if achievement.type == "song": + owned_songs.add(achievement.id) + elif achievement.type == "secret": + owned_secrets.add(achievement.id) + # Player info and statistics info = Node.void("info") player.add_child(info) @@ -393,11 +425,9 @@ class JubeatSaucerFulfill( item.add_child( Node.s32_array( "secret_list", - profile.get_int_array( - "secret_list", - 32, - [-1] * 32, - ), + ([-1] * 32) + if force_unlock + else self.create_owned_items(owned_songs, 32), ) ) item.add_child( @@ -427,11 +457,9 @@ class JubeatSaucerFulfill( new.add_child( Node.s32_array( "secret_list", - profile.get_int_array( - "secret_list_new", - 32, - [-1] * 32, - ), + ([-1] * 32) + if force_unlock + else self.create_owned_items(owned_secrets, 32), ) ) new.add_child( @@ -771,6 +799,11 @@ class JubeatSaucerFulfill( newprofile.replace_bool("saved", True) data = request.child("data") + # Figure out if we're force-unlocking songs. If we are, we don't want to persist + # secret stuff otherwise the game will accidentally unlock everything in the profile. + game_config = self.get_game_config() + force_unlock = game_config.get_bool("force_song_unlock") + # Grab player information player = data.child("player") @@ -813,9 +846,6 @@ class JubeatSaucerFulfill( # Grab unlock progress item = player.child("item") if item is not None: - newprofile.replace_int_array( - "secret_list", 32, item.child_value("secret_list") - ) newprofile.replace_int_array( "title_list", 96, item.child_value("title_list") ) @@ -826,9 +856,6 @@ class JubeatSaucerFulfill( newprofile.replace_int_array( "parts_list", 96, item.child_value("parts_list") ) - newprofile.replace_int_array( - "secret_list_new", 32, item.child_value("secret_new") - ) newprofile.replace_int_array( "title_list_new", 96, item.child_value("title_new") ) @@ -837,6 +864,34 @@ class JubeatSaucerFulfill( "marker_list_new", 2, item.child_value("marker_new") ) + if not force_unlock: + # Don't persist if we're force-unlocked, this data will be bogus. + owned_songs = self.calculate_owned_items( + item.child_value("secret_list") + ) + for index in owned_songs: + self.data.local.user.put_achievement( + self.game, + self.version, + userid, + index, + "song", + {}, + ) + + owned_secrets = self.calculate_owned_items( + item.child_value("secret_new") + ) + for index in owned_secrets: + self.data.local.user.put_achievement( + self.game, + self.version, + userid, + index, + "secret", + {}, + ) + # Grab macchiato event macchiatodict = newprofile.get_dict("macchiato") macchiato = player.child("macchiato")